敢为人鲜小程序前端代码仓库
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.

385 lines
12 KiB

2 months ago
  1. <template>
  2. <view class="place-order">
  3. <uv-popup ref="popup" @change="change" mode="bottom">
  4. <view class="place-order-content">
  5. <view class="place-order-title">
  6. <image src="@/static/image/多人下单.webp" mode="aspectFit" class="place-order-title-image" />
  7. <text class="number">{{ item.sales }}</text><text class="text">人下单</text>
  8. <view class="place-order-title-close" @click="close">
  9. <uv-icon name="close" size="40rpx" />
  10. </view>
  11. </view>
  12. <!-- 选择取餐地点 -->
  13. <view class="place-order-address" @click="gotoPickupPoint">
  14. <uv-icon name="map-fill" color="#019245" size="55rpx" />
  15. <text style="font-size: 42rpx;" v-show="!pickupPoint">
  16. 请选择取餐地点
  17. </text>
  18. <view v-if="pickupPoint" class="place-order-address-content">
  19. <view class="place-order-address-content-name">
  20. {{ pickupPoint.name }}{{ pickupPoint.phone }}
  21. </view>
  22. <view class="place-order-address-content-address"> {{ pickupPoint.area }} {{ pickupPoint.address
  23. }} </view>
  24. </view>
  25. <view class="place-order-address-arrow">
  26. <uv-icon name="arrow-right" size="40rpx" />
  27. </view>
  28. </view>
  29. <uv-gap height="20rpx" bgColor="#F7F7F7" />
  30. <!-- 货品信息 -->
  31. <view class="item">
  32. <image :src="item.image" mode="aspectFill" class="item-image"></image>
  33. <view style="font-size: 36rpx;">
  34. <view>{{ item.name }}</view>
  35. <view style="color: red; ">{{ priceAll }}</view>
  36. <view style="color: red; ">实付{{ pricePay }}</view>
  37. <view style="margin-top: 30rpx;">
  38. <uv-number-box v-model="value" button-size="36"></uv-number-box>
  39. </view>
  40. </view>
  41. </view>
  42. <!-- 选项框 -->
  43. <uv-radio-group v-model="payMethod">
  44. <view class="option-box">
  45. <view class="option-box-item">
  46. <uv-icon name="weixin-circle-fill" size="70rpx" color="#019245" />
  47. <text style="flex: 1;">
  48. 微信支付
  49. </text>
  50. <uv-radio activeColor="#019245" size="40rpx" name="0" />
  51. </view>
  52. <view class="option-box-item">
  53. <uv-icon name="red-packet" size="70rpx" color="#019245" />
  54. <text style="flex: 1;">
  55. 账户余额
  56. <text style="color: gray; margin-left: 20rpx;">(余额: {{ userInfo.balance ?
  57. userInfo.balance.toFixed(2) : 0 }})</text>
  58. </text>
  59. <uv-radio activeColor="#019245" size="40rpx" name="1" :disabled="userInfo.balance < pricePay" />
  60. </view>
  61. </view>
  62. </uv-radio-group>
  63. <uv-gap height="20rpx" bgColor="#F7F7F7" />
  64. <!-- 优惠 -->
  65. <view class="discount">
  66. <text style="font-size: 35rpx;">优惠</text>
  67. <view style="display: flex; align-items: center; gap: 20rpx" @click="gotoCoupon">
  68. <image src="@/static/image/券.webp" mode="aspectFill" class="discount-image"
  69. v-if="couponData.id" />
  70. <text v-if="couponData.id">{{ couponData.couponId_dictText || '优惠卷' }}</text>
  71. <text v-else style="color: gray;">请选择您的优惠卷</text>
  72. <text style="color: red;" v-if="couponData.discount">-{{ couponData.discount || 0 }}</text>
  73. </view>
  74. </view>
  75. <uv-gap height="20rpx" bgColor="#F7F7F7" />
  76. <!-- 备注 -->
  77. <view class="remark">
  78. <text style="align-self: start;">备注</text>
  79. <textarea class="remark-textarea" placeholder="请输入您需要备注的内容" v-model="remark" />
  80. </view>
  81. <!-- 购物车与支付 -->
  82. <view class="cart-pay">
  83. <view class="cart" @click="$emit('addCart')">
  84. <uv-icon name="shopping-cart-fill" size="60rpx" color="#019245" label="加入购物车" labelPos="bottom"
  85. labelSize="25rpx" />
  86. </view>
  87. <view class="pay" @tap="createOrder">
  88. 立即支付
  89. </view>
  90. </view>
  91. </view>
  92. </uv-popup>
  93. </view>
  94. </template>
  95. <script>
  96. import { mapState, mapMutations } from 'vuex'
  97. export default {
  98. name: 'placeOrder',
  99. data() {
  100. return {
  101. value: 1,
  102. payMethod: '0',
  103. pickupPoint: null,
  104. remark: '',
  105. }
  106. },
  107. props: {
  108. item: {
  109. type: Object,
  110. default: () => {}
  111. }
  112. },
  113. computed: {
  114. ...mapState(['userInfo', 'couponData']),
  115. priceAll () {
  116. return this.item.price * this.value
  117. },
  118. goodss () {
  119. return `${this.item.id},${this.value},${this.priceAll};`
  120. },
  121. pricePay () {
  122. return (this.priceAll - ( this.couponData.discount || 0 )) > 0 ? (this.priceAll - ( this.couponData.discount || 0 )) : 0.01
  123. }
  124. },
  125. methods: {
  126. ...mapMutations(['clearCouponData']),
  127. // 跳转到优惠卷选择页面
  128. gotoCoupon() {
  129. this.$utils.navigateTo('/pages_order/mine/coupon?usein=1')
  130. },
  131. // 添加open方法,用于外部调用打开弹窗
  132. open() {
  133. this.$refs.popup.open();
  134. },
  135. // 添加close方法,用于关闭弹窗
  136. close(){
  137. this.$refs.popup.close();
  138. },
  139. // 添加change方法,用于处理弹窗状态变化
  140. change(e) {
  141. console.log('弹窗状态变化:', e);
  142. // 可以在这里添加弹窗打开或关闭后的逻辑处理
  143. },
  144. // 跳转到取餐点选择页面
  145. gotoPickupPoint() {
  146. this.$utils.navigateTo('/pages_order/location/pickupPoint')
  147. },
  148. // 获取并监听取餐点选择事件
  149. listenPickupPoint() {
  150. const pickupPointStr = uni.getStorageSync('selectedPickupPoint');
  151. if (pickupPointStr) {
  152. this.pickupPoint = JSON.parse(pickupPointStr);
  153. }
  154. uni.$on('updatePickupPoint', (point) => {
  155. this.pickupPoint = point;
  156. })
  157. },
  158. // 创建订单
  159. createOrder(){
  160. if (!this.pickupPoint) {
  161. uni.showToast({
  162. title: '请选择取餐地点',
  163. icon: 'error'
  164. })
  165. return
  166. }
  167. if (this.payMethod == '1' && this.userInfo.balance < this.priceAll) {
  168. uni.showToast({
  169. title: '余额不足',
  170. icon: 'error'
  171. })
  172. return
  173. }
  174. uni.showLoading({
  175. title: '下单中...'
  176. })
  177. this.$api('createOrder', {
  178. priceAll: this.priceAll,
  179. pricePay: this.pricePay,
  180. pricePreferential: this.couponData.discount || 0,
  181. payType: this.payMethod,
  182. leaderId: this.pickupPoint.id,
  183. userCouponId: this.couponData.id || '',
  184. goodss: this.goodss,
  185. remark: this.remark
  186. }, res => {
  187. uni.hideLoading()
  188. if (res.code === 200) {
  189. if (this.payMethod == '0') {
  190. uni.requestPaymentWxPay(res)
  191. .then(n => {
  192. setTimeout(uni.redirectTo, 500, {
  193. url: '/pages/index/order?tabIndex=1'
  194. })
  195. })
  196. .catch(err => {
  197. uni.showToast({
  198. title: '支付失败',
  199. icon: 'error'
  200. })
  201. setTimeout(uni.redirectTo, 500, {
  202. url: '/pages/index/order?tabIndex=0'
  203. })
  204. })
  205. }else {
  206. uni.showToast({
  207. title: '下单成功',
  208. icon: 'success'
  209. })
  210. setTimeout(uni.redirectTo, 500, {
  211. url: '/pages/index/order?tabIndex=1'
  212. })
  213. }
  214. }
  215. })
  216. }
  217. },
  218. mounted(){
  219. this.listenPickupPoint();
  220. },
  221. beforeDestroy() {
  222. uni.$off('updatePickupPoint');
  223. this.clearCouponData();
  224. }
  225. }
  226. </script>
  227. <style lang="scss" scoped>
  228. .place-order-title{
  229. font-size: 35rpx;
  230. height: 90rpx;
  231. display: flex;
  232. align-items: center;
  233. justify-content: center;
  234. position: relative;
  235. .number{
  236. color: $uni-color;
  237. }
  238. .text{
  239. color: #000;
  240. }
  241. .place-order-title-image{
  242. width: 100rpx;
  243. height: 50rpx;
  244. }
  245. .place-order-title-close{
  246. position: absolute;
  247. right: 20rpx;
  248. top: 50%;
  249. transform: translateY(-50%);
  250. color: $uni-color-third;
  251. }
  252. }
  253. .place-order-address{
  254. display: flex;
  255. height: 80rpx;
  256. line-height: 80rpx;
  257. align-items: center;
  258. // background-color: red;
  259. gap: 30rpx;
  260. padding-left: 20rpx;
  261. position: relative;
  262. text{
  263. font-size: 32rpx;
  264. font-weight: 500;
  265. }
  266. &-arrow{
  267. position: absolute;
  268. right: 20rpx;
  269. top: 50%;
  270. transform: translateY(-50%);
  271. }
  272. &-content{
  273. display: flex;
  274. flex-direction: column;
  275. justify-content: space-around;
  276. gap: 0rpx;
  277. height: 100%;
  278. // width: 100%;
  279. &-name{
  280. height: 30rpx;
  281. line-height: 30rpx;
  282. }
  283. &-address{
  284. height: 30rpx;
  285. line-height: 30rpx;
  286. width: 90%;
  287. text-overflow: ellipsis; // 三个连着一起才会出现省略号
  288. overflow: hidden;
  289. white-space: nowrap;
  290. }
  291. }
  292. }
  293. .item{
  294. display: flex;
  295. padding: 40rpx;
  296. gap: 40rpx;
  297. &-image{
  298. width: 250rpx;
  299. height: 200rpx;
  300. }
  301. }
  302. .option-box{
  303. display: flex;
  304. flex-direction: column;
  305. gap: 40rpx;
  306. width: 100%;
  307. &-item{
  308. display: flex;
  309. gap: 20rpx;
  310. align-items: center;
  311. font-size: 32rpx;
  312. padding: 0 40rpx;
  313. }
  314. }
  315. .discount{
  316. height: 130rpx;
  317. display: flex;
  318. align-items: center;
  319. width: 90%;
  320. justify-content: space-between;
  321. padding:0rpx 40rpx 0rpx 40rpx;
  322. // gap: 20rpx;
  323. .discount-image{
  324. width: 36rpx;
  325. height: 36rpx;
  326. border-radius: 10rpx;
  327. }
  328. }
  329. .remark{
  330. display: flex;
  331. align-items: center;
  332. justify-content: space-between;
  333. padding: 20rpx 40rpx;
  334. // background-color: red;
  335. text{
  336. font-size: 32rpx;
  337. font-weight: 500;
  338. }
  339. .remark-textarea{
  340. width: 80%;
  341. height: 180rpx;
  342. // border: 1rpx solid #000;
  343. // border-radius: 10rpx;
  344. // padding: 20rpx;
  345. }
  346. }
  347. .cart-pay{
  348. // background-color: red;
  349. height: 130rpx;
  350. display: flex;
  351. .cart{
  352. width: 30%;
  353. display: flex;
  354. align-items: center;
  355. justify-content: center;
  356. }
  357. .pay{
  358. width: 70%;
  359. background-color: $uni-color;
  360. color: #fff;
  361. text-align: center;
  362. display: flex;
  363. align-items: center;
  364. justify-content: center;
  365. font-size: 32rpx;
  366. }
  367. }
  368. </style>