Browse Source

🐛 修复代码冲突,被错误覆盖掉的 cart.vue、pay.vue、result.vue、confirm.vue

YunaiV 1 năm trước cách đây
mục cha
commit
77e2719837

+ 381 - 407
pages/order/confirm.vue

@@ -1,414 +1,388 @@
 <template>
-	<s-layout title="确认订单">
-		<!-- v-if="state.orderInfo.need_address === 1" -->
-		<!-- 这个判断先删除 -->
-		<view class="bg-white address-box ss-m-b-14 ss-r-b-10" @tap="onSelectAddress">
-			<s-address-item :item="state.addressInfo" :hasBorderBottom="false">
-				<view class="ss-rest-button"><text class="_icon-forward"></text></view>
-			</s-address-item>
-		</view>
-		<view class="order-card-box ss-m-b-14">
-			<s-goods-item v-for="item in state.orderInfo.goods_list" :key="item.goods_id"
-				:img="item.current_sku_price.image || item.goods.image" :title="item.goods.title"
-				:skuText="item.current_sku_price?.goods_sku_text" :price="item.current_sku_price.price"
-				:num="item.goods_num" marginBottom="10">
-				<template #top>
-					<view class="order-item ss-flex ss-col-center ss-row-between ss-p-x-20 bg-white">
-						<view class="item-title">配送方式</view>
-						<view class="ss-flex ss-col-center">
-							<text class="item-value">{{ item.dispatch_type_text }}</text>
-						</view>
-					</view>
-				</template>
-			</s-goods-item>
-
-			<view class="order-item ss-flex ss-col-center ss-row-between ss-p-x-20 bg-white ss-r-10">
-				<view class="item-title">订单备注</view>
-				<view class="ss-flex ss-col-center">
-					<uni-easyinput maxlength="20" placeholder="建议留言前先与商家沟通" v-model="state.orderPayload.remark"
-						:inputBorder="false" :clearable="false"></uni-easyinput>
-				</view>
-			</view>
-		</view>
-		<!-- 合计 -->
-		<view class="bg-white total-card-box ss-p-20 ss-m-b-14 ss-r-10">
-			<view class="total-box-content border-bottom">
-				<view class="order-item ss-flex ss-col-center ss-row-between">
-					<view class="item-title">商品金额</view>
-					<view class="ss-flex ss-col-center">
-						<text class="item-value ss-m-r-24">¥{{ state.orderInfo.goods_amount }}</text>
-					</view>
-				</view>
-				<view class="order-item ss-flex ss-col-center ss-row-between"
-					v-if="state.orderPayload.order_type === 'score'">
-					<view class="item-title">扣除积分</view>
-					<view class="ss-flex ss-col-center">
-						<image :src="sheep.$url.static('/static/img/shop/goods/score1.svg')" class="score-img"></image>
-						<text class="item-value ss-m-r-24">{{ state.orderInfo.score_amount }}</text>
-					</view>
-				</view>
-				<view class="order-item ss-flex ss-col-center ss-row-between">
-					<view class="item-title">运费</view>
-					<view class="ss-flex ss-col-center">
-						<text class="item-value ss-m-r-24">+¥{{ state.orderInfo.dispatch_amount }}</text>
-					</view>
-				</view>
-				<view class="order-item ss-flex ss-col-center ss-row-between"
-					v-if="state.orderPayload.order_type != 'score'">
-					<!-- <view v-if="state.orderInfo.coupon_discount_fee > 0" class="order-item ss-flex ss-col-center ss-row-between"> -->
-					<view class="item-title">优惠券</view>
-					<view class="ss-flex ss-col-center" @tap="state.showCoupon = true">
-						<text class="item-value text-red"
-							v-if="state.orderPayload.coupon_id">-¥{{ state.orderInfo.coupon_discount_fee }}</text>
-						<text class="item-value"
-							:class="state.couponInfo.can_use?.length > 0 ? 'text-red' : 'text-disabled'" v-else>{{
-                state.couponInfo.can_use?.length > 0
-                  ? state.couponInfo.can_use?.length + '张可用'
-                  : '暂无可用优惠券'
-              }}</text>
-
-						<text class="_icon-forward item-icon"></text>
-					</view>
-				</view>
-				<view class="order-item ss-flex ss-col-center ss-row-between"
-					v-if="state.orderInfo.promo_infos?.length">
-					<!-- <view v-if="state.orderInfo.promo_discount_fee > 0" class="order-item ss-flex ss-col-center ss-row-between"> -->
-					<view class="item-title">活动优惠</view>
-					<view class="ss-flex ss-col-center" @tap="state.showDiscount = true">
-						<text class="item-value text-red"> -¥{{ state.orderInfo.promo_discount_fee }} </text>
-						<text class="_icon-forward item-icon"></text>
-					</view>
-				</view>
-			</view>
-			<view class="total-box-footer ss-font-28 ss-flex ss-row-right ss-col-center ss-m-r-28">
-				<view class="total-num ss-m-r-20">共{{ state.totalNumber }}件</view>
-				<view>合计:</view>
-				<view class="total-num text-red"> ¥{{ state.orderInfo.pay_fee }} </view>
-				<view class="ss-flex" v-if="state.orderPayload.order_type === 'score'">
-					<view class="total-num ss-font-30 text-red ss-m-l-4"> + </view>
-					<image :src="sheep.$url.static('/static/img/shop/goods/score1.svg')" class="score-img"></image>
-					<view class="total-num ss-font-30 text-red">{{ state.orderInfo.score_amount }}</view>
-				</view>
-			</view>
-		</view>
-		<!-- 发票 -->
-		<view class="bg-white ss-p-20 ss-r-20">
-			<view class="order-item ss-flex ss-col-center ss-row-between">
-				<view class="item-title">发票申请</view>
-				<view class="ss-flex ss-col-center" @tap="onSelectInvoice">
-					<text class="item-value">{{ state.invoiceInfo.name || '无需开具发票' }}</text>
-					<text class="_icon-forward item-icon"></text>
-				</view>
-			</view>
-		</view>
-		<!-- 选择优惠券弹框 -->
-		<s-coupon-select v-model="state.couponInfo" :show="state.showCoupon" @confirm="onSelectCoupon"
-			@close="state.showCoupon = false" />
-		<!-- 满额折扣弹框  -->
-		<s-discount-list v-model="state.orderInfo" :show="state.showDiscount" @close="state.showDiscount = false" />
-		<!-- 底部 -->
-		<su-fixed bottom :opacity="false" bg="bg-white" placeholder :noFixed="false" :index="200">
-			<view class="footer-box border-top ss-flex ss-row-between ss-p-x-20 ss-col-center">
-				<view class="total-box-footer ss-flex ss-col-center">
-					<view class="total-num ss-font-30 text-red"> ¥{{ state.orderInfo.pay_fee }} </view>
-					<view v-if="state.orderPayload.order_type === 'score'" class="ss-flex">
-						<view class="total-num ss-font-30 text-red ss-m-l-4">+</view>
-						<image :src="sheep.$url.static('/static/img/shop/goods/score1.svg')" class="score-img"></image>
-						<view class="total-num ss-font-30 text-red">{{ state.orderInfo.score_amount }}</view>
-					</view>
-				</view>
-
-				<button class="ss-reset-button ui-BG-Main-Gradient ss-r-40 submit-btn ui-Shadow-Main" @tap="onConfirm">
-					{{ exchangeNow ? '立即兑换' : '提交订单' }}
-				</button>
-			</view>
-		</su-fixed>
-	</s-layout>
+  <s-layout title="确认订单">
+    <!-- TODO:这个判断先删除 v-if="state.orderInfo.need_address === 1" -->
+    <view class="bg-white address-box ss-m-b-14 ss-r-b-10" @tap="onSelectAddress">
+      <s-address-item :item="state.addressInfo" :hasBorderBottom="false">
+        <view class="ss-rest-button">
+          <text class="_icon-forward" />
+        </view>
+      </s-address-item>
+    </view>
+
+    <!-- 商品信息 -->
+    <view class="order-card-box ss-m-b-14">
+      <s-goods-item
+        v-for="item in state.orderInfo.items"
+        :key="item.skuId"
+        :img="item.picUrl"
+        :title="item.spuName"
+        :skuText="item.properties.map((property) => property.valueName).join(' ')"
+        :price="item.price"
+        :num="item.count"
+        marginBottom="10"
+      />
+      <view class="order-item ss-flex ss-col-center ss-row-between ss-p-x-20 bg-white ss-r-10">
+        <view class="item-title">订单备注</view>
+        <view class="ss-flex ss-col-center">
+          <uni-easyinput
+            maxlength="20"
+            placeholder="建议留言前先与商家沟通"
+            v-model="state.orderPayload.remark"
+            :inputBorder="false"
+            :clearable="false"
+          />
+        </view>
+      </view>
+    </view>
+
+    <!-- 价格信息 -->
+    <view class="bg-white total-card-box ss-p-20 ss-m-b-14 ss-r-10">
+      <view class="total-box-content border-bottom">
+        <view class="order-item ss-flex ss-col-center ss-row-between">
+          <view class="item-title">商品金额</view>
+          <view class="ss-flex ss-col-center">
+            <text class="item-value ss-m-r-24">
+              ¥{{ fen2yuan(state.orderInfo.price.totalPrice) }}
+            </text>
+          </view>
+        </view>
+        <!-- TODO 芋艿:接入积分 -->
+        <view
+          class="order-item ss-flex ss-col-center ss-row-between"
+          v-if="state.orderPayload.order_type === 'score'"
+        >
+          <view class="item-title">扣除积分</view>
+          <view class="ss-flex ss-col-center">
+            <image
+              :src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
+              class="score-img"
+            />
+            <text class="item-value ss-m-r-24">{{ state.orderInfo.score_amount }}</text>
+          </view>
+        </view>
+        <view class="order-item ss-flex ss-col-center ss-row-between">
+          <view class="item-title">运费</view>
+          <view class="ss-flex ss-col-center">
+            <text class="item-value ss-m-r-24">
+              +¥{{ fen2yuan(state.orderInfo.price.deliveryPrice) }}
+            </text>
+          </view>
+        </view>
+        <!-- 优惠劵:只有 type = 0 普通订单(非拼团、秒杀、砍价),才可以使用优惠劵 -->
+        <view
+          class="order-item ss-flex ss-col-center ss-row-between"
+          v-if="state.orderInfo.type === 0"
+        >
+          <view class="item-title">优惠券</view>
+          <view class="ss-flex ss-col-center" @tap="state.showCoupon = true">
+            <text class="item-value text-red" v-if="state.orderPayload.couponId > 0">
+              -¥{{ fen2yuan(state.orderInfo.price.couponPrice) }}
+            </text>
+            <text
+              class="item-value"
+              :class="state.couponInfo.length > 0 ? 'text-red' : 'text-disabled'"
+              v-else
+            >
+              {{
+                state.couponInfo.length > 0 ? state.couponInfo.length + ' 张可用' : '暂无可用优惠券'
+              }}
+            </text>
+            <text class="_icon-forward item-icon" />
+          </view>
+        </view>
+        <view
+          class="order-item ss-flex ss-col-center ss-row-between"
+          v-if="state.orderInfo.price.discountPrice > 0"
+        >
+          <view class="item-title">活动优惠</view>
+          <view class="ss-flex ss-col-center">
+            <!--                @tap="state.showDiscount = true" TODO 芋艿:后续要把优惠信息打进去 -->
+            <text class="item-value text-red">
+              -¥{{ fen2yuan(state.orderInfo.price.discountPrice) }}
+            </text>
+            <text class="_icon-forward item-icon" />
+          </view>
+        </view>
+      </view>
+      <view class="total-box-footer ss-font-28 ss-flex ss-row-right ss-col-center ss-m-r-28">
+        <view class="total-num ss-m-r-20">
+          共{{ state.orderInfo.items.reduce((acc, item) => acc + item.count, 0) }}件
+        </view>
+        <view>合计:</view>
+        <view class="total-num text-red"> ¥{{ fen2yuan(state.orderInfo.price.payPrice) }} </view>
+      </view>
+    </view>
+
+    <!-- 选择优惠券弹框 -->
+    <s-coupon-select
+      v-model="state.couponInfo"
+      :show="state.showCoupon"
+      @confirm="onSelectCoupon"
+      @close="state.showCoupon = false"
+    />
+
+    <!-- 满额折扣弹框 TODO 芋艿:后续要把优惠信息打进去 -->
+    <s-discount-list
+      v-model="state.orderInfo"
+      :show="state.showDiscount"
+      @close="state.showDiscount = false"
+    />
+
+    <!-- 底部 -->
+    <su-fixed bottom :opacity="false" bg="bg-white" placeholder :noFixed="false" :index="200">
+      <view class="footer-box border-top ss-flex ss-row-between ss-p-x-20 ss-col-center">
+        <view class="total-box-footer ss-flex ss-col-center">
+          <view class="total-num ss-font-30 text-red">
+            ¥{{ fen2yuan(state.orderInfo.price.payPrice) }}
+          </view>
+        </view>
+        <button
+          class="ss-reset-button ui-BG-Main-Gradient ss-r-40 submit-btn ui-Shadow-Main"
+          @tap="onConfirm"
+        >
+          提交订单
+        </button>
+      </view>
+    </su-fixed>
+  </s-layout>
 </template>
 
 <script setup>
-	import {
-		reactive,
-		computed
-	} from 'vue';
-	import {
-		onLoad,
-		onPageScroll,
-		onShow
-	} from '@dcloudio/uni-app';
-	import sheep from '@/sheep';
-	import {
-		isEmpty
-	} from 'lodash';
-
-	const state = reactive({
-		orderPayload: {},
-		orderInfo: {},
-		addressInfo: {},
-		invoiceInfo: {},
-		totalNumber: 0,
-		showCoupon: false,
-		couponInfo: [],
-		showDiscount: false,
-	});
-
-	// 立即兑换(立即兑换无需跳转收银台)
-	const exchangeNow = computed(
-		() => state.orderPayload.order_type === 'score' && state.orderInfo.pay_fee == 0,
-	);
-
-	// 选择地址
-	function onSelectAddress() {
-		uni.$once('SELECT_ADDRESS', (e) => {
-			changeConsignee(e.addressInfo);
-		});
-		sheep.$router.go('/pages/user/address/list');
-	}
-
-	// 更改收货人地址&计算订单信息
-	async function changeConsignee(addressInfo = {}) {
-		if (isEmpty(addressInfo)) {
-			const {
-				code,
-				data
-			} = await sheep.$api.user.address.default();
-			console.log(data, '默认收货地址');
-			if (code === 0 && !isEmpty(data)) {
-				console.log('执行赋值')
-				addressInfo = data;
-			}
-		}
-		if (!isEmpty(addressInfo)) {
-			state.addressInfo = addressInfo;
-			state.orderPayload.address_id = state.addressInfo.id;
-		}
-		getOrderInfo();
-	}
-
-	// 选择优惠券
-	async function onSelectCoupon(e) {
-		state.orderPayload.coupon_id = e || 0;
-		getOrderInfo();
-		state.showCoupon = false;
-	}
-
-	// 选择发票信息
-	function onSelectInvoice() {
-		uni.$once('SELECT_INVOICE', (e) => {
-			state.invoiceInfo = e.invoiceInfo;
-			state.orderPayload.invoice_id = e.invoiceInfo.id || 0;
-		});
-		sheep.$router.go('/pages/user/invoice/list');
-	}
-
-	// 提交订单/立即兑换
-	function onConfirm() {
-		if (!state.orderPayload.address_id && state.orderInfo.need_address === 1) {
-			sheep.$helper.toast('请选择收货地址');
-			return;
-		}
-
-		if (exchangeNow.value) {
-			uni.showModal({
-				title: '提示',
-				content: '确定使用积分立即兑换?',
-				cancelText: '再想想',
-				success: async function(res) {
-					if (res.confirm) {
-						submitOrder();
-					}
-				},
-			});
-		} else {
-			submitOrder();
-		}
-	}
-
-	// 创建订单&跳转
-	async function submitOrder() {
-		const {
-			error,
-			data
-		} = await sheep.$api.order.create(state.orderPayload);
-		if (error === 0) {
-			// 更新购物车列表
-			if (state.orderPayload.from === 'cart') {
-				sheep.$store('cart').getList();
-			}
-			if (exchangeNow.value) {
-				sheep.$router.redirect('/pages/pay/result', {
-					orderSN: data.order_sn,
-				});
-			} else {
-				sheep.$router.redirect('/pages/pay/index', {
-					orderSN: data.order_sn,
-				});
-			}
-		}
-	}
-
-	// 检查库存&计算订单价格
-	async function getOrderInfo() {
-		console.log(state.orderPayload, '计算价格传参')
-		// let {code, data} = await sheep.$api.order.calc(state.orderPayload);
-		// let data = await sheep.$api.order.calc(state.orderPayload);
-		console.log(state.orderPayload.items)
-		let data = await sheep.$api.order.calc({
-			deliveryType: 1,
-			pointStatus: false,
-			items: state.orderPayload.items
-		});
-		console.log(data, '修改后的获取订单详细数据')
-		return;
-		if (error === 0) {
-			state.totalNumber = 0;
-			state.orderInfo = data;
-			state.orderInfo.goods_list.forEach((item) => {
-				state.totalNumber += item.goods_num;
-			});
-		}
-	}
-
-	// 获取可用优惠券
-	async function getCoupons() {
-		const {
-			error,
-			data
-		} = await sheep.$api.order.coupons(state.orderPayload);
-		if (error === 0) {
-			state.couponInfo = data;
-		}
-	}
-
-	onLoad(async (options) => {
-		console.log(options)
-		if (options.data) {
-			state.orderPayload = JSON.parse(options.data);
-			changeConsignee();
-			if (state.orderPayload.order_type !== 'score') {
-				getCoupons();
-			}
-		}
-	});
+  import { reactive } from 'vue';
+  import { onLoad } from '@dcloudio/uni-app';
+  import sheep from '@/sheep';
+  import { isEmpty } from 'lodash';
+  import OrderApi from '@/sheep/api/trade/order';
+  import CouponApi from '@/sheep/api/promotion/coupon';
+  import { fen2yuan } from '@/sheep/hooks/useGoods';
+
+  const state = reactive({
+    orderPayload: {},
+    orderInfo: {
+      items: [], // 商品项列表
+      price: {}, // 价格信息
+    },
+    addressInfo: {}, // 选择的收货地址
+    showCoupon: false, // 是否展示优惠劵
+    couponInfo: [], // 优惠劵列表
+    showDiscount: false, // 是否展示营销活动
+  });
+
+  // 选择地址
+  function onSelectAddress() {
+    uni.$once('SELECT_ADDRESS', (e) => {
+      changeConsignee(e.addressInfo);
+    });
+    sheep.$router.go('/pages/user/address/list');
+  }
+
+  // 更改收货人地址&计算订单信息
+  async function changeConsignee(addressInfo = {}) {
+    if (!isEmpty(addressInfo)) {
+      state.addressInfo = addressInfo;
+    }
+    await getOrderInfo();
+  }
+
+  // 选择优惠券
+  async function onSelectCoupon(couponId) {
+    state.orderPayload.couponId = couponId || 0;
+    await getOrderInfo();
+    state.showCoupon = false;
+  }
+
+  // 提交订单
+  function onConfirm() {
+    if (!state.addressInfo.id) {
+      sheep.$helper.toast('请选择收货地址');
+      return;
+    }
+    submitOrder();
+  }
+
+  // 创建订单&跳转
+  async function submitOrder() {
+    const { code, data } = await OrderApi.createOrder({
+      items: state.orderPayload.items,
+      couponId: state.orderPayload.couponId,
+      addressId: state.addressInfo.id,
+      deliveryType: 1, // TODO 芋艿:需要支持【门店自提】
+      pointStatus: false, // TODO 芋艿:需要支持【积分选择】
+    });
+    if (code !== 0) {
+      return;
+    }
+    // 更新购物车列表,如果来自购物车
+    if (state.orderPayload.items[0].cartId > 0) {
+      sheep.$store('cart').getList();
+    }
+    // 跳转到支付页面
+    sheep.$router.redirect('/pages/pay/index', {
+      id: data.payOrderId,
+    });
+  }
+
+  // 检查库存 & 计算订单价格
+  async function getOrderInfo() {
+    // 计算价格
+    const { data, code } = await OrderApi.settlementOrder({
+      items: state.orderPayload.items,
+      couponId: state.orderPayload.couponId,
+      addressId: state.addressInfo.id,
+      deliveryType: 1, // TODO 芋艿:需要支持【门店自提】
+      pointStatus: false, // TODO 芋艿:需要支持【积分选择】
+    });
+    if (code !== 0) {
+      return;
+    }
+    state.orderInfo = data;
+    // 设置收货地址
+    if (state.orderInfo.address) {
+      state.addressInfo = state.orderInfo.address;
+    }
+  }
+
+  // 获取可用优惠券
+  async function getCoupons() {
+    const { code, data } = await CouponApi.getMatchCouponList(
+      state.orderInfo.price.payPrice,
+      state.orderInfo.items.map((item) => item.spuId),
+      state.orderPayload.items.map((item) => item.skuId),
+      state.orderPayload.items.map((item) => item.categoryId),
+    );
+    if (code === 0) {
+      state.couponInfo = data;
+    }
+  }
+
+  onLoad(async (options) => {
+    if (!options.data) {
+      sheep.$helper.toast('参数不正确,请检查!');
+      return;
+    }
+    state.orderPayload = JSON.parse(options.data);
+    await getOrderInfo();
+    await getCoupons();
+  });
 </script>
 
 <style lang="scss" scoped>
-	:deep() {
-		.uni-input-wrapper {
-			width: 320rpx;
-		}
-
-		.uni-easyinput__content-input {
-			font-size: 28rpx;
-			height: 72rpx;
-			text-align: right !important;
-			padding-right: 0 !important;
-
-			.uni-input-input {
-				font-weight: 500;
-				color: #333333;
-				font-size: 26rpx;
-				height: 32rpx;
-				margin-top: 4rpx;
-			}
-		}
-
-		.uni-easyinput__content {
-			display: flex !important;
-			align-items: center !important;
-			justify-content: right !important;
-		}
-	}
-
-	.score-img {
-		width: 36rpx;
-		height: 36rpx;
-		margin: 0 4rpx;
-	}
-
-	.order-item {
-		height: 80rpx;
-
-		.item-title {
-			font-size: 28rpx;
-			font-weight: 400;
-		}
-
-		.item-value {
-			font-size: 28rpx;
-			font-weight: 500;
-			font-family: OPPOSANS;
-		}
-
-		.text-disabled {
-			color: #bbbbbb;
-		}
-
-		.item-icon {
-			color: $dark-9;
-		}
-
-		.remark-input {
-			text-align: right;
-		}
-
-		.item-placeholder {
-			color: $dark-9;
-			font-size: 26rpx;
-			text-align: right;
-		}
-	}
-
-	.total-box-footer {
-		height: 90rpx;
-
-		.total-num {
-			color: #333333;
-			font-family: OPPOSANS;
-		}
-	}
-
-	.footer-box {
-		height: 100rpx;
-
-		.submit-btn {
-			width: 240rpx;
-			height: 70rpx;
-			font-size: 28rpx;
-			font-weight: 500;
-
-			.goto-pay-text {
-				line-height: 28rpx;
-			}
-		}
-
-		.cancel-btn {
-			width: 240rpx;
-			height: 80rpx;
-			font-size: 26rpx;
-			background-color: #e5e5e5;
-			color: $dark-9;
-		}
-	}
-
-	.title {
-		font-size: 36rpx;
-		font-weight: bold;
-		color: #333333;
-	}
-
-	.subtitle {
-		font-size: 28rpx;
-		color: #999999;
-	}
-
-	.cicon-checkbox {
-		font-size: 36rpx;
-		color: var(--ui-BG-Main);
-	}
-
-	.cicon-box {
-		font-size: 36rpx;
-		color: #999999;
-	}
-</style>
+  :deep() {
+    .uni-input-wrapper {
+      width: 320rpx;
+    }
+
+    .uni-easyinput__content-input {
+      font-size: 28rpx;
+      height: 72rpx;
+      text-align: right !important;
+      padding-right: 0 !important;
+
+      .uni-input-input {
+        font-weight: 500;
+        color: #333333;
+        font-size: 26rpx;
+        height: 32rpx;
+        margin-top: 4rpx;
+      }
+    }
+
+    .uni-easyinput__content {
+      display: flex !important;
+      align-items: center !important;
+      justify-content: right !important;
+    }
+  }
+
+  .score-img {
+    width: 36rpx;
+    height: 36rpx;
+    margin: 0 4rpx;
+  }
+
+  .order-item {
+    height: 80rpx;
+
+    .item-title {
+      font-size: 28rpx;
+      font-weight: 400;
+    }
+
+    .item-value {
+      font-size: 28rpx;
+      font-weight: 500;
+      font-family: OPPOSANS;
+    }
+
+    .text-disabled {
+      color: #bbbbbb;
+    }
+
+    .item-icon {
+      color: $dark-9;
+    }
+
+    .remark-input {
+      text-align: right;
+    }
+
+    .item-placeholder {
+      color: $dark-9;
+      font-size: 26rpx;
+      text-align: right;
+    }
+  }
+
+  .total-box-footer {
+    height: 90rpx;
+
+    .total-num {
+      color: #333333;
+      font-family: OPPOSANS;
+    }
+  }
+
+  .footer-box {
+    height: 100rpx;
+
+    .submit-btn {
+      width: 240rpx;
+      height: 70rpx;
+      font-size: 28rpx;
+      font-weight: 500;
+
+      .goto-pay-text {
+        line-height: 28rpx;
+      }
+    }
+
+    .cancel-btn {
+      width: 240rpx;
+      height: 80rpx;
+      font-size: 26rpx;
+      background-color: #e5e5e5;
+      color: $dark-9;
+    }
+  }
+
+  .title {
+    font-size: 36rpx;
+    font-weight: bold;
+    color: #333333;
+  }
+
+  .subtitle {
+    font-size: 28rpx;
+    color: #999999;
+  }
+
+  .cicon-checkbox {
+    font-size: 36rpx;
+    color: var(--ui-BG-Main);
+  }
+
+  .cicon-box {
+    font-size: 36rpx;
+    color: #999999;
+  }
+</style>

+ 54 - 124
pages/pay/index.vue

@@ -2,14 +2,17 @@
 <template>
   <s-layout title="收银台">
     <view class="bg-white ss-modal-box ss-flex-col">
+      <!-- 订单信息 -->
       <view class="modal-header ss-flex-col ss-col-center ss-row-center">
         <view class="money-box ss-m-b-20">
-          <text class="money-text">{{ state.orderInfo.pay_fee }}</text>
+          <text class="money-text">{{ fen2yuan(state.orderInfo.price) }}</text>
         </view>
         <view class="time-text">
           <text>{{ payDescText }}</text>
         </view>
       </view>
+
+      <!-- 支付方式 -->
       <view class="modal-content ss-flex-1">
         <view class="pay-title ss-p-l-30 ss-m-y-30">选择支付方式</view>
         <radio-group @change="onTapPay">
@@ -17,7 +20,6 @@
             <view
               class="pay-item ss-flex ss-col-center ss-row-between ss-p-x-30 border-bottom"
               :class="{ 'disabled-pay-item': item.disabled }"
-              v-if="allowedPayment.includes(item.value)"
             >
               <view class="ss-flex ss-col-center">
                 <image
@@ -25,25 +27,19 @@
                   v-if="item.disabled"
                   :src="sheep.$url.static('/static/img/shop/pay/cod_disabled.png')"
                   mode="aspectFit"
-                ></image>
+                />
                 <image
                   class="pay-icon"
                   v-else
                   :src="sheep.$url.static(item.icon)"
                   mode="aspectFit"
-                ></image>
+                />
                 <text class="pay-title">{{ item.title }}</text>
               </view>
               <view class="check-box ss-flex ss-col-center ss-p-l-10">
-                <view class="userInfo-money ss-m-r-10" v-if="item.value == 'money'">
+                <view class="userInfo-money ss-m-r-10" v-if="item.value === 'wallet'">
                   余额: {{ userInfo.money }}元
                 </view>
-                <view
-                  class="userInfo-money ss-m-r-10"
-                  v-if="item.value == 'offline' && item.disabled"
-                >
-                  部分商品不支持
-                </view>
                 <radio
                   :value="item.value"
                   color="var(--ui-BG-Main)"
@@ -56,6 +52,7 @@
           </label>
         </radio-group>
       </view>
+
       <!-- 工具 -->
       <view class="modal-footer ss-flex ss-row-center ss-col-center ss-m-t-80 ss-m-b-40">
         <button v-if="state.payStatus === 0" class="ss-reset-button past-due-btn">
@@ -81,95 +78,49 @@
   import { computed, reactive } from 'vue';
   import { onLoad } from '@dcloudio/uni-app';
   import sheep from '@/sheep';
-  import { useDurationTime } from '@/sheep/hooks/useGoods';
+  import { fen2yuan, useDurationTime } from '@/sheep/hooks/useGoods';
+  import PayOrderApi from '@/sheep/api/pay/order';
+  import PayChannelApi from '@/sheep/api/pay/channel';
+  import { getPayMethods } from '@/sheep/platform/pay';
 
   const userInfo = computed(() => sheep.$store('user').userInfo);
 
   // 检测支付环境
   const state = reactive({
-    orderType: 'goods',
-    payment: '',
-    orderInfo: {},
+    orderType: 'goods', // 订单类型; goods - 商品订单, recharge - 充值订单
+    orderInfo: {}, // 支付单信息
     payStatus: 0, // 0=检测支付环境, -2=未查询到支付单信息, -1=支付已过期, 1=待支付,2=订单已支付
-    payMethods: [],
+    payMethods: [], // 可选的支付方式
+    payment: '', // 选中的支付方式
   });
 
-  const allowedPayment = computed(() => {
-    if(state.orderType === 'recharge') {
-      return sheep.$store('app').platform.recharge_payment
-    }
-    return sheep.$store('app').platform.payment
-    });
-
-  const payMethods = [
-    {
-      icon: '/static/img/shop/pay/wechat.png',
-      title: '微信支付',
-      value: 'wechat',
-      disabled: false,
-    },
-    {
-      icon: '/static/img/shop/pay/alipay.png',
-      title: '支付宝支付',
-      value: 'alipay',
-      disabled: false,
-    },
-    {
-      icon: '/static/img/shop/pay/wallet.png',
-      title: '余额支付',
-      value: 'money',
-      disabled: false,
-    },
-    {
-      icon: '/static/img/shop/pay/apple.png',
-      title: 'Apple Pay',
-      value: 'apple',
-      disabled: false,
-    },
-    {
-      icon: '/static/img/shop/pay/cod.png',
-      title: '货到付款',
-      value: 'offline',
-      disabled: false,
-    },
-  ];
-
   const onPay = () => {
     if (state.payment === '') {
       sheep.$helper.toast('请选择支付方式');
       return;
     }
-    if (state.payment === 'money') {
+    if (state.payment === 'wallet') {
       uni.showModal({
         title: '提示',
         content: '确定要支付吗?',
         success: function (res) {
           if (res.confirm) {
-            sheep.$platform.pay(state.payment, state.orderType, state.orderInfo.order_sn);
-          }
-        },
-      });
-    } else if (state.payment === 'offline') {
-      uni.showModal({
-        title: '提示',
-        content: '确定要下单吗?',
-        success: function (res) {
-          if (res.confirm) {
-            sheep.$platform.pay(state.payment, state.orderType, state.orderInfo.order_sn);
+            sheep.$platform.pay(state.payment, state.orderType, state.orderInfo.id);
           }
         },
       });
     } else {
-      sheep.$platform.pay(state.payment, state.orderType, state.orderInfo.order_sn);
+      sheep.$platform.pay(state.payment, state.orderType, state.orderInfo.id);
     }
   };
 
+  // 支付文案提示
   const payDescText = computed(() => {
     if (state.payStatus === 2) {
       return '该订单已支付';
     }
-    if (state.payStatus === 1 && state.orderInfo.ext.expired_time !== 0) {
-      const time = useDurationTime(state.orderInfo.ext.expired_time);
+    if (state.payStatus === 1) {
+      const time = useDurationTime(state.orderInfo.expireTime);
       if (time.ms <= 0) {
         state.payStatus = -1;
         return '';
@@ -179,86 +130,65 @@
     if (state.payStatus === -2) {
       return '未查询到支付单信息';
     }
-
     return '';
   });
 
+  // 状态转换:payOrder.status => payStatus
   function checkPayStatus() {
-    if (state.orderInfo.status === 'unpaid') {
-      state.payStatus = 1;
+    if (state.orderInfo.status === 10
+      || state.orderInfo.status === 20 ) { // 支付成功
+      state.payStatus = 2;
       return;
     }
-    if (state.orderInfo.status === 'closed') {
+    if (state.orderInfo.status === 30) { // 支付关闭
       state.payStatus = -1;
       return;
     }
-    state.payStatus = 2;
+    state.payStatus = 1; // 待支付
   }
 
+  // 切换支付方式
   function onTapPay(e) {
     state.payment = e.detail.value;
   }
 
-  async function setRechargeOrder(id) {
-    const { data, error } = await sheep.$api.trade.order(id);
-    if (error === 0) {
-      state.orderInfo = data;
-      state.payMethods = payMethods;
-      checkPayStatus();
-    } else {
+  // 设置支付订单信息
+  async function setOrder(id) {
+    // 获得支付订单信息
+    const { data, code } = await PayOrderApi.getOrder(id);
+    if (code !== 0 || !data) {
       state.payStatus = -2;
+      return;
     }
+    state.orderInfo = data;
+    // 获得支付方式
+    await setPayMethods();
+    // 设置支付状态
+    checkPayStatus();
   }
 
-  async function setGoodsOrder(id) {
-    const { data, error } = await sheep.$api.order.detail(id);
-    if (error === 0) {
-      state.orderInfo = data;
-      if (state.orderInfo.ext.offline_status === 'none') {
-        payMethods.forEach((item, index, array) => {
-          if (item.value === 'offline') {
-            array.splice(index, 1);
-          }
-        });
-      } else if (state.orderInfo.ext.offline_status === 'disabled') {
-        payMethods.forEach((item) => {
-          if (item.value === 'offline') {
-            item.disabled = true;
-          }
-        });
-      }
-      state.payMethods = payMethods;
-      checkPayStatus();
-    } else {
-      state.payStatus = -2;
+  // 获得支付方式
+  async function setPayMethods() {
+    const { data, code } = await PayChannelApi.getEnableChannelCodeList(state.orderInfo.appId)
+    if (code !== 0) {
+      return
     }
+    state.payMethods = getPayMethods(data)
   }
 
   onLoad((options) => {
-    if (
-      sheep.$platform.name === 'WechatOfficialAccount' &&
-      sheep.$platform.os === 'ios' &&
-      !sheep.$platform.landingPage.includes('pages/pay/index')
-    ) {
+    if (sheep.$platform.name === 'WechatOfficialAccount'
+      && sheep.$platform.os === 'ios'
+      && !sheep.$platform.landingPage.includes('pages/pay/index')) {
       location.reload();
       return;
     }
-    let id = '';
-    if (options.orderSN) {
-      id = options.orderSN;
-    }
-    if (options.id) {
-      id = options.id;
-    }
-    if (options.type === 'recharge') {
-      state.orderType = 'recharge';
-      // 充值订单
-      setRechargeOrder(id);
-    } else {
-      state.orderType = 'goods';
-      // 商品订单
-      setGoodsOrder(id);
+    // 获得支付订单信息
+    let id = options.id;
+    if (options.orderType) {
+      state.orderType = options.orderType;
     }
+    setOrder(id);
   });
 </script>
 

+ 61 - 59
pages/pay/result.vue

@@ -2,34 +2,27 @@
 <template>
   <s-layout title="支付结果" :bgStyle="{ color: '#FFF' }">
     <view class="pay-result-box ss-flex-col ss-row-center ss-col-center">
-      <view class="pay-waiting ss-m-b-30" v-if="payResult === 'waiting'"> </view>
+      <!-- 信息展示 -->
+      <view class="pay-waiting ss-m-b-30" v-if="payResult === 'waiting'" />
       <image
         class="pay-img ss-m-b-30"
         v-if="payResult === 'success'"
         :src="sheep.$url.static('/static/img/shop/order/order_pay_success.gif')"
-      ></image>
+      />
       <image
         class="pay-img ss-m-b-30"
         v-if="['failed', 'closed'].includes(payResult)"
         :src="sheep.$url.static('/static/img/shop/order/order_paty_fail.gif')"
-      ></image>
-      <view class="tip-text ss-m-b-30" v-if="payResult == 'success'">{{
-        state.orderInfo.pay_mode === 'offline' ? '下单成功' : '支付成功'
-      }}</view>
-      <view class="tip-text ss-m-b-30" v-if="payResult == 'failed'">支付失败</view>
-      <view class="tip-text ss-m-b-30" v-if="payResult == 'closed'">该订单已关闭</view>
-      <view class="tip-text ss-m-b-30" v-if="payResult == 'waiting'">检测支付结果...</view>
+      />
+      <view class="tip-text ss-m-b-30" v-if="payResult === 'success'">支付成功</view>
+      <view class="tip-text ss-m-b-30" v-if="payResult === 'failed'">支付失败</view>
+      <view class="tip-text ss-m-b-30" v-if="payResult === 'closed'">该订单已关闭</view>
+      <view class="tip-text ss-m-b-30" v-if="payResult === 'waiting'">检测支付结果...</view>
       <view class="pay-total-num ss-flex" v-if="payResult === 'success'">
-        <view v-if="Number(state.orderInfo.pay_fee) > 0">¥{{ state.orderInfo.pay_fee }}</view>
-        <view v-if="state.orderInfo.score_amount && Number(state.orderInfo.pay_fee) > 0">+</view>
-        <view class="price-text ss-flex ss-col-center" v-if="state.orderInfo.score_amount">
-          <image
-            :src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
-            class="score-img"
-          ></image>
-          <view>{{ state.orderInfo.score_amount }}</view>
-        </view>
+        <view>¥{{ fen2yuan(state.orderInfo.price) }}</view>
       </view>
+
+      <!-- 操作区 -->
       <view class="btn-box ss-flex ss-row-center ss-m-t-50">
         <button class="back-btn ss-reset-button" @tap="sheep.$router.go('/pages/index/index')">
           返回首页
@@ -37,30 +30,29 @@
         <button
           class="check-btn ss-reset-button"
           v-if="payResult === 'failed'"
-          @tap="sheep.$router.redirect('/pages/pay/index', { orderSN: state.orderId })"
+          @tap="
+            sheep.$router.redirect('/pages/pay/index', { id: state.id, orderType: state.orderType })
+          "
         >
           重新支付
         </button>
         <button class="check-btn ss-reset-button" v-if="payResult === 'success'" @tap="onOrder">
           查看订单
         </button>
+        <!-- TODO 芋艿:拼团接入 -->
         <button
           class="check-btn ss-reset-button"
-          v-if="
-            payResult === 'success' &&
-            ['groupon', 'groupon_ladder'].includes(state.orderInfo.activity_type)
-          "
+          v-if="payResult === 'success' && state.tradeOrder.type === 3"
           @tap="sheep.$router.redirect('/pages/activity/groupon/order')"
         >
           我的拼团
         </button>
       </view>
+
+      <!-- TODO 芋艿:订阅 -->
       <!-- #ifdef MP -->
       <view class="subscribe-box ss-flex ss-m-t-44">
-        <image
-          class="subscribe-img"
-          :src="sheep.$url.static('/static/img/shop/order/cargo.png')"
-        ></image>
+        <image class="subscribe-img" :src="sheep.$url.static('/static/img/shop/order/cargo.png')" />
         <view class="subscribe-title ss-m-r-48 ss-m-l-16">获取实时发货信息与订单状态</view>
         <view class="subscribe-start" @tap="subscribeMessage">立即订阅</view>
       </view>
@@ -74,15 +66,20 @@
   import { reactive, computed } from 'vue';
   import { isEmpty } from 'lodash';
   import sheep from '@/sheep';
+  import PayOrderApi from '@/sheep/api/pay/order';
+  import { fen2yuan } from '../../sheep/hooks/useGoods';
+  import OrderApi from '@/sheep/api/trade/order';
 
   const state = reactive({
-    orderId: 0,
-    orderType: 'goods',
+    id: 0, // 支付单号
+    orderType: 'goods', // 订单类型
     result: 'unpaid', // 支付状态
-    orderInfo: {}, // 订单详情
+    orderInfo: {}, // 支付订单信息
+    tradeOrder: {}, // 商品订单信息,只有在 orderType 为 goods 才会请求。目的:【我的拼团】按钮的展示
     counter: 0, // 获取结果次数
   });
 
+  // 支付结果 result => payResult
   const payResult = computed(() => {
     if (state.result === 'unpaid') {
       return 'waiting';
@@ -93,57 +90,65 @@
     if (state.result === 'failed') {
       return 'failed';
     }
-
     if (state.result === 'closed') {
       return 'closed';
     }
   });
-  async function getOrderInfo(orderId) {
-    let checkPayResult;
+
+  // 获得订单信息
+  async function getOrderInfo(id) {
     state.counter++;
-    if (state.orderType === 'recharge') {
-      checkPayResult = sheep.$api.trade.order;
-    } else {
-      checkPayResult = sheep.$api.order.detail;
-    }
-    const { data, error } = await checkPayResult(orderId);
-    if (error === 0) {
+    // 1. 加载订单信息
+    const { data, code } = await PayOrderApi.getOrder(id);
+    if (code === 0) {
       state.orderInfo = data;
-      if (state.orderInfo.status === 'closed') {
+      if (!state.orderInfo || state.orderInfo.status === 30) {
+        // 支付关闭
         state.result = 'closed';
         return;
       }
-      if (state.orderInfo.status !== 'unpaid') {
+      if (state.orderInfo.status !== 0) {
+        // 非待支付,可能是已支付,可能是已退款
         state.result = 'paid';
         // #ifdef MP
         subscribeMessage();
         // #endif
+        // 特殊:获得商品订单信息
+        if (state.orderType === 'goods') {
+          const { data, code } = await OrderApi.getOrder(state.orderInfo.merchantOrderId);
+          if (code === 0) {
+            state.tradeOrder = data;
+          }
+        }
         return;
       }
     }
+    // 2.1 情况三一:未支付,且轮询次数小于三次,则继续轮询
     if (state.counter < 3 && state.result === 'unpaid') {
       setTimeout(() => {
-        getOrderInfo(orderId);
+        getOrderInfo(id);
       }, 1500);
     }
-    // 超过三次检测才判断为支付失败
+    // 2.2 情况二:超过三次检测才判断为支付失败
     if (state.counter >= 3) {
       state.result = 'failed';
     }
   }
 
   function onOrder() {
-    if ((state.orderType === 'recharge')) {
+    // TODO 芋艿:待测试
+    if (state.orderType === 'recharge') {
       sheep.$router.redirect('/pages/pay/recharge-log');
     } else {
       sheep.$router.redirect('/pages/order/list');
     }
   }
 
+  // TODO 芋艿:待测试
   // #ifdef MP
   function subscribeMessage() {
     let event = ['order_dispatched'];
-    if (['groupon', 'groupon_ladder'].includes(state.orderInfo.activity_type)) {
+    if (state.tradeOrder.type === 3) {
       event.push('groupon_finish');
       event.push('groupon_fail');
     }
@@ -152,18 +157,13 @@
   // #endif
 
   onLoad(async (options) => {
-    let id = '';
     // 支付订单号
-    if (options.orderSN) {
-      id = options.orderSN;
-    }
     if (options.id) {
-      id = options.id;
+      state.id = options.id;
     }
-    state.orderId = id;
-
-    if (options.orderType === 'recharge') {
-      state.orderType = 'recharge';
+    // 订单类型
+    if (options.orderType) {
+      state.orderType = options.orderType;
     }
 
     // 支付结果传值过来是失败,则直接显示失败界面
@@ -171,14 +171,16 @@
       state.result = 'failed';
     } else {
       // 轮询三次检测订单支付结果
-      getOrderInfo(state.orderId);
+      await getOrderInfo(state.id);
     }
   });
 
   onShow(() => {
-    if(isEmpty(state.orderInfo)) return;
-    getOrderInfo(state.orderId);
-  })
+    if (isEmpty(state.orderInfo)) {
+      return;
+    }
+    getOrderInfo(state.id);
+  });
 
   onHide(() => {
     state.result = 'unpaid';

+ 14 - 0
sheep/api/pay/channel.js

@@ -0,0 +1,14 @@
+import request from '@/sheep/request';
+
+const PayChannelApi = {
+  // 获得指定应用的开启的支付渠道编码列表
+  getEnableChannelCodeList: (appId) => {
+    return request({
+      url: '/app-api/pay/channel/get-enable-code-list',
+      method: 'GET',
+      params: { appId }
+    });
+  },
+};
+
+export default PayChannelApi;

+ 22 - 0
sheep/api/pay/order.js

@@ -0,0 +1,22 @@
+import request from '@/sheep/request';
+
+const PayOrderApi = {
+  // 获得支付订单
+  getOrder: (id) => {
+    return request({
+      url: '/app-api/pay/order/get',
+      method: 'GET',
+      params: { id }
+    });
+  },
+  // 提交支付订单
+  submitOrder: (data) => {
+    return request({
+      url: '/app-api/pay/order/submit',
+      method: 'POST',
+      data
+    });
+  }
+};
+
+export default PayOrderApi;

+ 47 - 0
sheep/api/trade/cart.js

@@ -0,0 +1,47 @@
+import request2 from '@/sheep/request2';
+
+const CartApi = {
+  addCart: (data) => {
+    return request2({
+      url: '/app-api/trade/cart/add',
+      method: 'POST',
+      data: data,
+      // TODO 芋艿:这里没提示
+      custom: {
+        showSuccess: true,
+        successMsg: '已添加到购物车~',
+      }
+    });
+  },
+  updateCartCount: (data) => {
+    return request2({
+      url: '/app-api/trade/cart/update-count',
+      method: 'PUT',
+      data: data
+    });
+  },
+  updateCartSelected: (data) => {
+    return request2({
+      url: '/app-api/trade/cart/update-selected',
+      method: 'PUT',
+      data: data
+    });
+  },
+  deleteCart: (ids) => {
+    return request2({
+      url: '/app-api/trade/cart/delete',
+      method: 'DELETE',
+      params: {
+        ids
+      }
+    });
+  },
+  getCartList: () => {
+    return request2({
+      url: '/app-api/trade/cart/list',
+      method: 'GET',
+    });
+  },
+};
+
+export default CartApi;

+ 103 - 0
sheep/api/trade/order.js

@@ -0,0 +1,103 @@
+import request2 from '@/sheep/request2';
+import request from '@/sheep/request';
+
+const OrderApi = {
+  // 计算订单信息
+  settlementOrder: (data) => {
+    const data2 = {
+      ...data,
+    };
+    // 移除多余字段
+    if (!(data.couponId > 0)) {
+      delete data2.couponId;
+    }
+    if (!(data.addressId > 0)) {
+      delete data2.addressId;
+    }
+    // 解决 SpringMVC 接受 List<Item> 参数的问题
+    delete data2.items;
+    for (let i = 0; i < data.items.length; i++) {
+      data2[encodeURIComponent('items[' + i + '' + '].skuId')] = data.items[i].skuId + '';
+      data2[encodeURIComponent('items[' + i + '' + '].count')] = data.items[i].count + '';
+      if (data.items[i].cartId) {
+        data2[encodeURIComponent('items[' + i + '' + '].cartId')] = data.items[i].cartId + '';
+      }
+    }
+    const queryString = Object.keys(data2)
+      .map((key) => key + '=' + data2[key])
+      .join('&');
+    return request2({
+      url: `trade/order/settlement?${queryString}`,
+      method: 'GET',
+    });
+  },
+  // 创建订单
+  createOrder: (data) => {
+    return request2({
+      url: `trade/order/create`,
+      method: 'POST',
+      data,
+    });
+  },
+  // 获得订单
+  getOrder: (id) => {
+    return request2({
+      url: `trade/order/get-detail`,
+      method: 'GET',
+      params: {
+        id,
+      },
+    });
+  },
+  // 订单列表
+  getOrderPage: (params) => {
+    return request({
+      url: '/app-api/trade/order/page',
+      method: 'GET',
+      params,
+      custom: {
+        showLoading: false,
+      },
+    });
+  },
+  // 确认收货
+  receiveOrder: (id) => {
+    return request2({
+      url: `/app-api/trade/order/receive`,
+      method: 'PUT',
+      params: {
+        id,
+      },
+    });
+  },
+  // 取消订单
+  cancelOrder: (id) => {
+    return request2({
+      url: `/app-api/trade/order/cancel`,
+      method: 'DELETE',
+      params: {
+        id,
+      },
+    });
+  },
+  // 删除订单
+  deleteOrder: (id) => {
+    return request2({
+      url: `/app-api/trade/order/delete`,
+      method: 'DELETE',
+      params: {
+        id,
+      },
+    });
+  },
+  // 创建单个评论
+  createOrderItemComment: (data) => {
+    return request2({
+      url: `/app-api/trade/order/item/create-comment`,
+      method: 'POST',
+      data,
+    });
+  },
+};
+
+export default OrderApi;

+ 99 - 33
sheep/platform/pay.js

@@ -3,19 +3,20 @@ import sheep from '@/sheep';
 import $wxsdk from '@/sheep/libs/sdk-h5-weixin';
 // #endif
 import { getRootUrl } from '@/sheep/helper';
+import PayOrderApi from '@/sheep/api/pay/order';
 
 /**
  * 支付
  *
  * @param {String} payment = ['wechat','alipay','wallet','offline']  	- 支付方式
  * @param {String} orderType = ['goods','recharge','groupon']  	- 订单类型
- * @param {String} orderSN					- 订单号
+ * @param {String} id					- 订单号
  */
 
 export default class SheepPay {
-  constructor(payment, orderType, orderSN) {
+  constructor(payment, orderType, id) {
     this.payment = payment;
-    this.orderSN = orderSN;
+    this.id = id;
     this.orderType = orderType;
     this.payAction();
   }
@@ -29,8 +30,8 @@ export default class SheepPay {
         alipay: () => {
           this.redirectPay(); // 现在公众号可以直接跳转支付宝页面
         },
-        money: () => {
-          this.moneyPay();
+        wallet: () => {
+          this.walletPay();
         },
         offline: () => {
           this.offlinePay();
@@ -43,8 +44,8 @@ export default class SheepPay {
         alipay: () => {
           this.copyPayLink();
         },
-        money: () => {
-          this.moneyPay();
+        wallet: () => {
+          this.walletPay();
         },
         offline: () => {
           this.offlinePay();
@@ -57,8 +58,8 @@ export default class SheepPay {
         alipay: () => {
           this.alipay();
         },
-        money: () => {
-          this.moneyPay();
+        wallet: () => {
+          this.walletPay();
         },
         offline: () => {
           this.offlinePay();
@@ -71,8 +72,8 @@ export default class SheepPay {
         alipay: () => {
           this.redirectPay();
         },
-        money: () => {
-          this.moneyPay();
+        wallet: () => {
+          this.walletPay();
         },
         offline: () => {
           this.offlinePay();
@@ -83,18 +84,21 @@ export default class SheepPay {
   }
 
   // 预支付
-  prepay() {
+  prepay(channel) {
     return new Promise((resolve, reject) => {
       let data = {
-        order_sn: this.orderSN,
-        payment: this.payment,
+        id: this.id,
+        channelCode: channel,
+        channelExtras: {}
       };
       if (uni.getStorageSync('openid')) {
         data.openid = uni.getStorageSync('openid');
       }
-      sheep.$api.pay.prepay(data).then((res) => {
-        res.error === 0 && resolve(res);
-        if (res.error === -1 && res.msg === 'miss_openid') {
+      PayOrderApi.submitOrder(data).then((res) => {
+        // 成功时
+        res.code === 0 && resolve(res);
+        // 失败时
+        if (res.code !== 0 && res.msg === 'miss_openid') {
           uni.showModal({
             title: '微信支付',
             content: '请先绑定微信再使用微信支付',
@@ -109,7 +113,7 @@ export default class SheepPay {
     });
   }
   // #ifdef H5
-  // 微信公众号JSSDK支付
+  // 微信公众号JSSDK支付 TODO 芋艿:待接入
   async wechatOfficialAccountPay() {
     let that = this;
     let { error, data, msg } = await this.prepay();
@@ -130,21 +134,21 @@ export default class SheepPay {
     });
   }
 
-  //浏览器微信H5支付
+  //浏览器微信H5支付 TODO 芋艿:待接入
   async wechatWapPay() {
     const { error, data } = await this.prepay();
     if (error === 0) {
-      const redirect_url = `${getRootUrl()}pages/pay/result?orderSN=${this.orderSN}&payment=${this.payment
+      const redirect_url = `${getRootUrl()}pages/pay/result?id=${this.id}&payment=${this.payment
         }&orderType=${this.orderType}`;
       location.href = `${data.pay_data.h5_url}&redirect_url=${encodeURIComponent(redirect_url)}`;
     }
   }
 
-  // 支付链接
+  // 支付链接  TODO 芋艿:待接入
   async redirectPay() {
     let { error, data } = await this.prepay();
     if (error === 0) {
-      const redirect_url = `${getRootUrl()}pages/pay/result?orderSN=${this.orderSN}&payment=${this.payment
+      const redirect_url = `${getRootUrl()}pages/pay/result?id=${this.id}&payment=${this.payment
         }&orderType=${this.orderType}`;
       location.href = data.pay_data + encodeURIComponent(redirect_url);
     }
@@ -152,7 +156,7 @@ export default class SheepPay {
 
   // #endif
 
-  // 微信小程序支付
+  // 微信小程序支付  TODO 芋艿:待接入
   async wechatMiniProgramPay() {
     let that = this;
     let result = await this.prepay();
@@ -173,18 +177,18 @@ export default class SheepPay {
   }
 
   // 余额支付
-  async moneyPay() {
-    const { error } = await this.prepay();
-    error === 0 && this.payResult('success');
+  async walletPay() {
+    const { code } = await this.prepay('wallet');
+    code === 0 && this.payResult('success');
   }
 
-  // 货到付款
+  // 货到付款  TODO 芋艿:待接入
   async offlinePay() {
     const { error } = await this.prepay();
     error === 0 && this.payResult('success');
   }
 
-  // 支付宝复制链接支付
+  // 支付宝复制链接支付  TODO 芋艿:待接入
   async copyPayLink() {
     let that = this;
     let { error, data } = await this.prepay();
@@ -203,7 +207,7 @@ export default class SheepPay {
     }
   }
 
-  // 支付宝支付
+  // 支付宝支付  TODO 芋艿:待接入
   async alipay() {
     let that = this;
     const { error, data } = await this.prepay();
@@ -225,7 +229,7 @@ export default class SheepPay {
     }
   }
 
-  // 微信支付
+  // 微信支付  TODO 芋艿:待接入
   async wechatAppPay() {
     let that = this;
     let { error, data } = await this.prepay();
@@ -246,10 +250,72 @@ export default class SheepPay {
   // 支付结果跳转,success:成功,fail:失败
   payResult(resultType) {
     sheep.$router.redirect('/pages/pay/result', {
-      orderSN: this.orderSN,
-      payment: this.payment, //重新支付的时候使用
-      payState: resultType,
+      id: this.id,
       orderType: this.orderType,
+      payState: resultType
     });
   }
 }
+
+export function getPayMethods(channels) {
+  const payMethods = [
+    {
+      icon: '/static/img/shop/pay/wechat.png',
+      title: '微信支付',
+      value: 'wechat',
+      disabled: true,
+    },
+    {
+      icon: '/static/img/shop/pay/alipay.png',
+      title: '支付宝支付',
+      value: 'alipay',
+      disabled: true,
+    },
+    {
+      icon: '/static/img/shop/pay/wallet.png',
+      title: '余额支付',
+      value: 'wallet',
+      disabled: true,
+    },
+    {
+      icon: '/static/img/shop/pay/apple.png',
+      title: 'Apple Pay',
+      value: 'apple',
+      disabled: true,
+    },
+    {
+      icon: '/static/img/shop/pay/wallet.png',
+      title: '模拟支付',
+      value: 'mock',
+      disabled: true,
+    }
+  ];
+  const platform = sheep.$platform.name
+
+  // 1. 处理【微信支付】
+  const wechatMethod = payMethods[0];
+  if ((platform === 'WechatOfficialAccount' && channels.includes('wx_pub'))
+    || platform === 'WechatMiniProgram' && channels.includes('wx_lite')
+    || platform === 'App' && channels.includes('wx_app')) {
+    wechatMethod.disabled = false;
+  }
+  // 2. 处理【支付宝支付】
+  const alipayMethod = payMethods[1];
+  if ((platform === 'WechatOfficialAccount' && channels.includes('alipay_wap'))
+    || platform === 'WechatMiniProgram' && channels.includes('alipay_wap')
+    || platform === 'App' && channels.includes('alipay_app')) {
+    alipayMethod.disabled = false;
+  }
+  // 3. 处理【余额支付】
+  const walletMethod = payMethods[2];
+  if (channels.includes('wallet')) {
+    walletMethod.disabled = false;
+  }
+  // 4. 处理【苹果支付】TODO 芋艿:未来接入
+  // 5. 处理【模拟支付】
+  const mockMethod = payMethods[4];
+  if (channels.includes('mock')) {
+    mockMethod.disabled = false;
+  }
+  return payMethods;
+}

+ 48 - 53
sheep/store/cart.js

@@ -1,98 +1,93 @@
 import { defineStore } from 'pinia';
-import cartApi from '@/sheep/api/cart';
+import CartApi from '@/sheep/api/trade/cart';
 
 const cart = defineStore({
   id: 'cart',
   state: () => ({
     list: [], // 购物车列表
     selectedIds: [], // 已选列表
-    isAllSelected: false, //是否全选
-    cartSelectedTotalPrice: '0.00', // 选中项总金额
+    isAllSelected: false, // 是否全选
+    totalPriceSelected: 0, // 选中项总金额
   }),
-  getters: {
-    totalPriceSelected: (state) => {
-      let price = 0;
-      if (!state.selectedIds.length) return price.toFixed(2);
-      state.list.forEach((item) => {
-        price += state.selectedIds.includes(item.id)
-          ? Number(item.sku.price/100) * item.count
-          : 0;
-      });
-      return price.toFixed(2);
-    },
-  },
   actions: {
     // 获取购物车列表
     async getList() {
-      const { data, code } = await cartApi.list();
+      const { data, code } = await CartApi.getCartList();
       if (code === 0) {
         this.list = data.validList;
+
+        // 计算各种关联属性
+        this.selectedIds = [];
+        this.isAllSelected = true;
+        this.totalPriceSelected = 0;
+        this.list.forEach((item) => {
+          if (item.selected) {
+            this.selectedIds.push(item.id);
+            this.totalPriceSelected += item.count * item.sku.price;
+          } else {
+            this.isAllSelected = false;
+          }
+        });
       }
     },
+
     // 添加购物车
     async add(goodsInfo) {
-      const { error } = await cartApi.append({
-        goods_id: goodsInfo.goods_id,
-        goods_num: goodsInfo.goods_num,
-        goods_sku_price_id: goodsInfo.id,
+      // 添加购物项
+      const { code } = await CartApi.addCart({
+        skuId: goodsInfo.id,
+        count: goodsInfo.goods_num,
       });
-      if (error === 0) {
-        this.getList();
+      // 刷新购物车列表
+      if (code === 0) {
+        await this.getList();
       }
     },
 
     // 更新购物车
     async update(goodsInfo) {
-      const { error } = await cartApi.update({
+      const { code } = await CartApi.updateCartCount({
         id: goodsInfo.goods_id,
         count: goodsInfo.goods_num,
-        goods_sku_price_id: goodsInfo.goods_sku_price_id,
       });
-      if (error === 0) {
-        // this.getList();
+      if (code === 0) {
+        await this.getList();
       }
     },
 
     // 移除购物车
     async delete(ids) {
-      if (typeof ids === 'array') {
-        ids = ids.join(',');
-      }
-      const { code } = await cartApi.delete(ids);
+      const { code } = await CartApi.deleteCart(ids.join(','));
       if (code === 0) {
-        this.selectAll(false);
-        this.getList();
+        await this.getList();
       }
     },
 
-    // 选择购物车商品
-    selectSingle(goodsId) {
-      if (!this.selectedIds.includes(goodsId)) {
-        this.selectedIds.push(goodsId);
-      } else {
-        this.selectedIds.splice(this.selectedIds.indexOf(goodsId), 1);
+    // 单选购物车商品
+    async selectSingle(goodsId) {
+      const { code } = await CartApi.updateCartSelected({
+        ids: [goodsId],
+        selected: !this.selectedIds.includes(goodsId), // 取反
+      });
+      if (code === 0) {
+        await this.getList();
       }
-      this.isAllSelected = this.selectedIds.length === this.list.length;
     },
 
-    // 全选
-    selectAll(flag) {
-      this.isAllSelected = flag;
-      if (!flag) {
-        this.selectedIds = [];
-      } else {
-        this.list.forEach((item) => {
-          this.selectedIds.push(item.id);
-        });
+    // 全选购物车商品
+    async selectAll(flag) {
+      const { code } = await CartApi.updateCartSelected({
+        ids: this.list.map((item) => item.id),
+        selected: flag
+      });
+      if (code === 0) {
+        await this.getList();
       }
     },
 
     // 清空购物车
-    emptyList() {
-      this.list = [];
-      this.selectedIds = [];
-      this.isAllSelected = false;
-      this.cartSelectedTotalPrice = '0.00';
+    async emptyList() {
+      await this.delete(this.list.map((item) => item.id));
     },
   },
   persist: {