Forráskód Böngészése

Merge branch 'develop' of https://gitee.com/yudaocode/yudao-mall-uniapp

YunaiV 10 hónapja
szülő
commit
25e4686e30
35 módosított fájl, 3942 hozzáadás és 1417 törlés
  1. 693 665
      pages.json
  2. 10 2
      pages/activity/index.vue
  3. 78 0
      pages/activity/point/list.vue
  4. 137 61
      pages/activity/seckill/list.vue
  5. 1 1
      pages/coupon/detail.vue
  6. 1 1
      pages/goods/comment/add.vue
  7. 249 31
      pages/goods/index.vue
  8. 10 1
      pages/goods/list.vue
  9. 525 0
      pages/goods/point.vue
  10. 7 2
      pages/goods/seckill.vue
  11. 1 1
      pages/order/aftersale/apply.vue
  12. 3 2
      pages/order/confirm.vue
  13. 9 5
      pages/order/detail.vue
  14. 8 8
      pages/order/express/log.vue
  15. 9 10
      pages/order/pickUpVerify.vue
  16. 26 15
      pages/pay/index.vue
  17. 4 1
      pages/pay/result.vue
  18. 4 4
      sheep/api/pay/order.js
  19. 12 0
      sheep/api/product/spu.js
  20. 30 0
      sheep/api/promotion/point.js
  21. 15 2
      sheep/api/trade/order.js
  22. 196 0
      sheep/components/countDown/index.vue
  23. 187 37
      sheep/components/s-activity-pop/s-activity-pop.vue
  24. 2 0
      sheep/components/s-block-item/s-block-item.vue
  25. 10 28
      sheep/components/s-discount-list/s-discount-list.vue
  26. 11 0
      sheep/components/s-goods-card/s-goods-card.vue
  27. 204 48
      sheep/components/s-goods-column/s-goods-column.vue
  28. 10 2
      sheep/components/s-goods-item/s-goods-item.vue
  29. 328 0
      sheep/components/s-point-block/s-point-block.vue
  30. 458 0
      sheep/components/s-point-card/s-point-card.vue
  31. 18 10
      sheep/components/s-select-seckill-sku/s-select-seckill-sku.vue
  32. 393 335
      sheep/components/s-select-sku/s-select-sku.vue
  33. 158 48
      sheep/hooks/useGoods.js
  34. 64 48
      sheep/platform/pay.js
  35. 71 49
      sheep/util/const.js

+ 693 - 665
pages.json

@@ -1,667 +1,695 @@
 {
-	"easycom": {
-		"autoscan": true,
-		"custom": {
-			"^s-(.*)": "@/sheep/components/s-$1/s-$1.vue",
-			"^su-(.*)": "@/sheep/ui/su-$1/su-$1.vue"
-		}
-	},
-	"pages": [{
-			"path": "pages/index/index",
-			"aliasPath": "/",
-			"style": {
-				"navigationBarTitleText": "首页",
-				"enablePullDownRefresh": true
-			},
-			"meta": {
-				"auth": false,
-				"sync": true,
-				"title": "首页",
-				"group": "商城"
-			}
-		},
-		{
-			"path": "pages/index/user",
-			"style": {
-				"navigationBarTitleText": "个人中心",
-				"enablePullDownRefresh": true
-			},
-			"meta": {
-				"sync": true,
-				"title": "个人中心",
-				"group": "商城"
-			}
-		},
-		{
-			"path": "pages/index/category",
-			"style": {
-				"navigationBarTitleText": "商品分类"
-			},
-			"meta": {
-				"sync": true,
-				"title": "商品分类",
-				"group": "商城"
-			}
-		},
-		{
-			"path": "pages/index/cart",
-			"style": {
-				"navigationBarTitleText": "购物车"
-			},
-			"meta": {
-				"sync": true,
-				"title": "购物车",
-				"group": "商城"
-			}
-		},
-		{
-			"path": "pages/index/login",
-			"style": {
-				"navigationBarTitleText": "登录"
-			}
-		},
-		{
-			"path": "pages/index/search",
-			"style": {
-				"navigationBarTitleText": "搜索"
-			},
-			"meta": {
-				"sync": true,
-				"title": "搜索",
-				"group": "商城"
-			}
-		},
-		{
-			"path": "pages/index/page",
-			"style": {
-				"navigationBarTitleText": ""
-			},
-			"meta": {
-				"auth": false,
-				"sync": true,
-				"title": "自定义页面",
-				"group": "商城"
-			}
-		}
-	],
-	"subPackages": [{
-			"root": "pages/goods",
-			"pages": [{
-					"path": "index",
-					"style": {
-						"navigationBarTitleText": "商品详情"
-					},
-					"meta": {
-						"sync": true,
-						"title": "普通商品",
-						"group": "商品"
-					}
-				},
-				{
-					"path": "groupon",
-					"style": {
-						"navigationBarTitleText": "拼团商品"
-					},
-					"meta": {
-						"sync": true,
-						"title": "拼团商品",
-						"group": "商品"
-					}
-				},
-
-				{
-					"path": "seckill",
-					"style": {
-						"navigationBarTitleText": "秒杀商品"
-					},
-					"meta": {
-						"sync": true,
-						"title": "秒杀商品",
-						"group": "商品"
-					}
-				},
-				{
-					"path": "list",
-					"style": {
-						"navigationBarTitleText": "商品列表"
-					},
-					"meta": {
-						"sync": true,
-						"title": "商品列表",
-						"group": "商品"
-					}
-				},
-				{
-					"path": "comment/add",
-					"style": {
-						"navigationBarTitleText": "评价商品"
-					},
-					"meta": {
-						"auth": true
-					}
-				},
-				{
-					"path": "comment/list",
-					"style": {
-						"navigationBarTitleText": "商品评价"
-					}
-				}
-			]
-		},
-		{
-			"root": "pages/order",
-			"pages": [{
-					"path": "detail",
-					"style": {
-						"navigationBarTitleText": "订单详情"
-					},
-					"meta": {
-						"auth": true,
-						"title": "订单详情"
-					}
-				},
-				{
-					"path": "confirm",
-					"style": {
-						"navigationBarTitleText": "确认订单"
-					},
-					"meta": {
-						"auth": true,
-						"title": "确认订单"
-					}
-				},
-				{
-					"path": "list",
-					"style": {
-						"navigationBarTitleText": "我的订单",
-						"enablePullDownRefresh": true
-					},
-					"meta": {
-						"auth": true,
-						"sync": true,
-						"title": "用户订单",
-						"group": "订单中心"
-					}
-				},
-				{
-					"path": "aftersale/apply",
-					"style": {
-						"navigationBarTitleText": "申请售后"
-					},
-					"meta": {
-						"auth": true,
-						"title": "申请售后"
-					}
-				},
-                {
-                  "path": "aftersale/return-delivery",
-                  "style": {
-                    "navigationBarTitleText": "退货物流"
-                  },
-                  "meta": {
-                    "auth": true,
-                    "title": "退货物流"
-                  }
-                },
-				{
-					"path": "aftersale/list",
-					"style": {
-						"navigationBarTitleText": "售后列表"
-					},
-					"meta": {
-						"auth": true,
-						"sync": true,
-						"title": "售后订单",
-						"group": "订单中心"
-					}
-				},
-				{
-					"path": "aftersale/detail",
-					"style": {
-						"navigationBarTitleText": "售后详情"
-					},
-					"meta": {
-						"auth": true,
-						"title": "售后详情"
-					}
-				},
-				{
-					"path": "aftersale/log",
-					"style": {
-						"navigationBarTitleText": "售后进度"
-					},
-					"meta": {
-						"auth": true,
-						"title": "售后进度"
-					}
-				},
-				{
-					"path": "express/log",
-					"style": {
-						"navigationBarTitleText": "物流轨迹"
-					},
-					"meta": {
-						"auth": true,
-						"title": "物流轨迹"
-					}
-				}
-			]
-		},
-		{
-			"root": "pages/user",
-			"pages": [{
-					"path": "info",
-					"style": {
-						"navigationBarTitleText": "我的信息"
-					},
-					"meta": {
-						"auth": true,
-						"sync": true,
-						"title": "用户信息",
-						"group": "用户中心"
-					}
-				},
-				{
-					"path": "goods-collect",
-					"style": {
-						"navigationBarTitleText": "我的收藏"
-					},
-					"meta": {
-						"auth": true,
-						"sync": true,
-						"title": "商品收藏",
-						"group": "用户中心"
-					}
-				},
-				{
-					"path": "goods-log",
-					"style": {
-						"navigationBarTitleText": "我的足迹"
-					},
-					"meta": {
-						"auth": true,
-						"sync": true,
-						"title": "浏览记录",
-						"group": "用户中心"
-					}
-				},
-				{
-					"path": "address/list",
-					"style": {
-						"navigationBarTitleText": "收货地址"
-					},
-					"meta": {
-						"auth": true,
-						"sync": true,
-						"title": "地址管理",
-						"group": "用户中心"
-					}
-				},
-				{
-					"path": "address/edit",
-					"style": {
-						"navigationBarTitleText": "编辑地址"
-					},
-					"meta": {
-						"auth": true,
-						"title": "编辑地址"
-					}
-				},
-                {
-                  "path": "goods_details_store/index",
-                  "style": {
-                    "navigationBarTitleText": "自提门店"
-                  },
-                  "meta": {
-                    "auth": true,
-                    "sync": true,
-                    "title": "地址管理",
-                    "group": "用户中心"
-                  }
-                },
-				{
-					"path": "wallet/money",
-					"style": {
-						"navigationBarTitleText": "我的余额"
-					},
-					"meta": {
-						"auth": true,
-						"sync": true,
-						"title": "用户余额",
-						"group": "用户中心"
-					}
-				},
-				{
-					"path": "wallet/score",
-					"style": {
-						"navigationBarTitleText": "我的积分"
-					},
-					"meta": {
-						"auth": true,
-						"sync": true,
-						"title": "用户积分",
-						"group": "用户中心"
-					}
-				}
-			]
-		},
-		{
-			"root": "pages/commission",
-			"pages": [{
-					"path": "index",
-					"style": {
-						"navigationBarTitleText": "分销"
-					},
-					"meta": {
-						"auth": true,
-						"sync": true,
-						"title": "分销中心",
-						"group": "分销商城"
-					}
-				},
-				{
-					"path": "wallet",
-					"style": {
-						"navigationBarTitleText": "我的佣金"
-					},
-					"meta": {
-						"auth": true,
-						"sync": true,
-						"title": "用户佣金",
-						"group": "分销中心"
-					}
-				},
-				{
-					"path": "goods",
-					"style": {
-						"navigationBarTitleText": "推广商品"
-					},
-					"meta": {
-						"auth": true,
-						"sync": true,
-						"title": "推广商品",
-						"group": "分销商城"
-					}
-				},
-				{
-					"path": "order",
-					"style": {
-						"navigationBarTitleText": "分销订单"
-					},
-					"meta": {
-						"auth": true,
-						"sync": true,
-						"title": "分销订单",
-						"group": "分销商城"
-					}
-				},
-				{
-					"path": "team",
-					"style": {
-						"navigationBarTitleText": "我的团队"
-					},
-					"meta": {
-						"auth": true,
-						"sync": true,
-						"title": "我的团队",
-						"group": "分销商城"
-					}
-				}, {
-					"path": "promoter",
-					"style": {
-						"navigationBarTitleText": "推广人排行榜"
-					},
-					"meta": {
-						"auth": true,
-						"sync": true,
-						"title": "推广人排行榜",
-						"group": "分销商城"
-					}
-				}, {
-					"path": "commission-ranking",
-					"style": {
-						"navigationBarTitleText": "佣金排行榜"
-					},
-					"meta": {
-						"auth": true,
-						"sync": true,
-						"title": "佣金排行榜",
-						"group": "分销商城"
-					}
-				}, {
-                "path": "withdraw",
-                "style": {
-                  "navigationBarTitleText": "申请提现"
-                },
-                "meta": {
-                  "auth": true,
-                  "sync": true,
-                  "title": "申请提现",
-                  "group": "分销商城"
-                }
-              }
-			]
-		},
-		{
-			"root": "pages/app",
-			"pages": [{
-				"path": "sign",
-				"style": {
-					"navigationBarTitleText": "签到中心"
-				},
-				"meta": {
-					"auth": true,
-					"sync": true,
-					"title": "签到中心",
-					"group": "应用"
-				}
-			}]
-		},
-		{
-			"root": "pages/public",
-			"pages": [{
-					"path": "setting",
-					"style": {
-						"navigationBarTitleText": "系统设置"
-					},
-					"meta": {
-						"sync": true,
-						"title": "系统设置",
-						"group": "通用"
-					}
-				},
-				{
-					"path": "richtext",
-					"style": {
-						"navigationBarTitleText": "富文本"
-					},
-					"meta": {
-						"sync": true,
-						"title": "富文本",
-						"group": "通用"
-					}
-				},
-				{
-					"path": "faq",
-					"style": {
-						"navigationBarTitleText": "常见问题"
-					},
-					"meta": {
-						"sync": true,
-						"title": "常见问题",
-						"group": "通用"
-					}
-				},
-				{
-					"path": "error",
-					"style": {
-						"navigationBarTitleText": "错误页面"
-					}
-				},
-				{
-					"path": "webview",
-					"style": {
-						"navigationBarTitleText": ""
-					}
-				}
-			]
-		},
-		{
-			"root": "pages/coupon",
-			"pages": [{
-					"path": "list",
-					"style": {
-						"navigationBarTitleText": "领券中心"
-					},
-					"meta": {
-						"sync": true,
-						"title": "领券中心",
-						"group": "优惠券"
-					}
-				},
-				{
-					"path": "detail",
-					"style": {
-						"navigationBarTitleText": "优惠券"
-					},
-					"meta": {
-						"auth": false,
-						"sync": true,
-						"title": "优惠券详情",
-						"group": "优惠券"
-					}
-				}
-			]
-		},
-		{
-			"root": "pages/chat",
-			"pages": [{
-				"path": "index",
-				"style": {
-					"navigationBarTitleText": "客服"
-				},
-				"meta": {
-					"auth": true,
-					"sync": true,
-					"title": "客服",
-					"group": "客服"
-				}
-			}]
-		},
-		{
-			"root": "pages/pay",
-			"pages": [{
-					"path": "index",
-					"style": {
-						"navigationBarTitleText": "收银台"
-					}
-				},
-				{
-					"path": "result",
-					"style": {
-						"navigationBarTitleText": "支付结果"
-					}
-				},
-				{
-					"path": "recharge",
-					"style": {
-						"navigationBarTitleText": "充值余额"
-					},
-					"meta": {
-						"auth": true,
-						"sync": true,
-						"title": "充值余额",
-						"group": "支付"
-					}
-				},
-				{
-					"path": "recharge-log",
-					"style": {
-						"navigationBarTitleText": "充值记录"
-					},
-					"meta": {
-						"auth": true,
-						"sync": true,
-						"title": "充值记录",
-						"group": "支付"
-					}
-				}
-			]
-		},
-		{
-			"root": "pages/activity",
-			"pages": [{
-					"path": "groupon/detail",
-					"style": {
-						"navigationBarTitleText": "拼团详情"
-					}
-				},
-				{
-					"path": "groupon/order",
-					"style": {
-						"navigationBarTitleText": "我的拼团",
-						"enablePullDownRefresh": true
-					},
-					"meta": {
-						"auth": true,
-						"sync": true,
-						"title": "拼团订单",
-						"group": "营销活动"
-					}
-				},
-				{
-					"path": "index",
-					"style": {
-						"navigationBarTitleText": "营销商品"
-					},
-					"meta": {
-						"sync": true,
-						"title": "营销商品",
-						"group": "营销活动"
-					}
-				},
-				{
-					"path": "groupon/list",
-					"style": {
-						"navigationBarTitleText": "拼团活动"
-					},
-					"meta": {
-						"sync": true,
-						"title": "拼团活动",
-						"group": "营销活动"
-					}
-				},
-				{
-					"path": "seckill/list",
-					"style": {
-						"navigationBarTitleText": "秒杀活动"
-					},
-					"meta": {
-						"sync": true,
-						"title": "秒杀活动",
-						"group": "营销活动"
-					}
-				}
-			]
-		}
-	],
-	"globalStyle": {
-		"navigationBarTextStyle": "black",
-		"navigationBarTitleText": "芋道商城",
-		"navigationBarBackgroundColor": "#FFFFFF",
-		"backgroundColor": "#FFFFFF",
-		"navigationStyle": "custom"
-	},
-	"tabBar": {
-		"list": [{
-				"pagePath": "pages/index/index"
-			},
-			{
-				"pagePath": "pages/index/cart"
-			},
-			{
-				"pagePath": "pages/index/user"
-			}
-		]
-	}
+  "easycom": {
+    "autoscan": true,
+    "custom": {
+      "^s-(.*)": "@/sheep/components/s-$1/s-$1.vue",
+      "^su-(.*)": "@/sheep/ui/su-$1/su-$1.vue"
+    }
+  },
+  "pages": [
+    {
+      "path": "pages/index/index",
+      "aliasPath": "/",
+      "style": {
+        "navigationBarTitleText": "首页",
+        "enablePullDownRefresh": true
+      },
+      "meta": {
+        "auth": false,
+        "sync": true,
+        "title": "首页",
+        "group": "商城"
+      }
+    },
+    {
+      "path": "pages/index/user",
+      "style": {
+        "navigationBarTitleText": "个人中心",
+        "enablePullDownRefresh": true
+      },
+      "meta": {
+        "sync": true,
+        "title": "个人中心",
+        "group": "商城"
+      }
+    },
+    {
+      "path": "pages/index/category",
+      "style": {
+        "navigationBarTitleText": "商品分类"
+      },
+      "meta": {
+        "sync": true,
+        "title": "商品分类",
+        "group": "商城"
+      }
+    },
+    {
+      "path": "pages/index/cart",
+      "style": {
+        "navigationBarTitleText": "购物车"
+      },
+      "meta": {
+        "sync": true,
+        "title": "购物车",
+        "group": "商城"
+      }
+    },
+    {
+      "path": "pages/index/login",
+      "style": {
+        "navigationBarTitleText": "登录"
+      }
+    },
+    {
+      "path": "pages/index/search",
+      "style": {
+        "navigationBarTitleText": "搜索"
+      },
+      "meta": {
+        "sync": true,
+        "title": "搜索",
+        "group": "商城"
+      }
+    },
+    {
+      "path": "pages/index/page",
+      "style": {
+        "navigationBarTitleText": ""
+      },
+      "meta": {
+        "auth": false,
+        "sync": true,
+        "title": "自定义页面",
+        "group": "商城"
+      }
+    }
+  ],
+  "subPackages": [
+    {
+      "root": "pages/goods",
+      "pages": [
+        {
+          "path": "index",
+          "style": {
+            "navigationBarTitleText": "商品详情"
+          },
+          "meta": {
+            "sync": true,
+            "title": "普通商品",
+            "group": "商品"
+          }
+        },
+        {
+          "path": "groupon",
+          "style": {
+            "navigationBarTitleText": "拼团商品"
+          },
+          "meta": {
+            "sync": true,
+            "title": "拼团商品",
+            "group": "商品"
+          }
+        },
+        {
+          "path": "seckill",
+          "style": {
+            "navigationBarTitleText": "秒杀商品"
+          },
+          "meta": {
+            "sync": true,
+            "title": "秒杀商品",
+            "group": "商品"
+          }
+        },
+        {
+          "path": "point",
+          "style": {
+            "navigationBarTitleText": "积分商品"
+          },
+          "meta": {
+            "sync": true,
+            "title": "积分商品",
+            "group": "商品"
+          }
+        },
+        {
+          "path": "list",
+          "style": {
+            "navigationBarTitleText": "商品列表"
+          },
+          "meta": {
+            "sync": true,
+            "title": "商品列表",
+            "group": "商品"
+          }
+        },
+        {
+          "path": "comment/add",
+          "style": {
+            "navigationBarTitleText": "评价商品"
+          },
+          "meta": {
+            "auth": true
+          }
+        },
+        {
+          "path": "comment/list",
+          "style": {
+            "navigationBarTitleText": "商品评价"
+          }
+        }
+      ]
+    },
+    {
+      "root": "pages/order",
+      "pages": [
+        {
+          "path": "detail",
+          "style": {
+            "navigationBarTitleText": "订单详情"
+          },
+          "meta": {
+            "auth": true,
+            "title": "订单详情"
+          }
+        },
+        {
+          "path": "confirm",
+          "style": {
+            "navigationBarTitleText": "确认订单"
+          },
+          "meta": {
+            "auth": true,
+            "title": "确认订单"
+          }
+        },
+        {
+          "path": "list",
+          "style": {
+            "navigationBarTitleText": "我的订单",
+            "enablePullDownRefresh": true
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "用户订单",
+            "group": "订单中心"
+          }
+        },
+        {
+          "path": "aftersale/apply",
+          "style": {
+            "navigationBarTitleText": "申请售后"
+          },
+          "meta": {
+            "auth": true,
+            "title": "申请售后"
+          }
+        },
+        {
+          "path": "aftersale/return-delivery",
+          "style": {
+            "navigationBarTitleText": "退货物流"
+          },
+          "meta": {
+            "auth": true,
+            "title": "退货物流"
+          }
+        },
+        {
+          "path": "aftersale/list",
+          "style": {
+            "navigationBarTitleText": "售后列表"
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "售后订单",
+            "group": "订单中心"
+          }
+        },
+        {
+          "path": "aftersale/detail",
+          "style": {
+            "navigationBarTitleText": "售后详情"
+          },
+          "meta": {
+            "auth": true,
+            "title": "售后详情"
+          }
+        },
+        {
+          "path": "aftersale/log",
+          "style": {
+            "navigationBarTitleText": "售后进度"
+          },
+          "meta": {
+            "auth": true,
+            "title": "售后进度"
+          }
+        },
+        {
+          "path": "express/log",
+          "style": {
+            "navigationBarTitleText": "物流轨迹"
+          },
+          "meta": {
+            "auth": true,
+            "title": "物流轨迹"
+          }
+        }
+      ]
+    },
+    {
+      "root": "pages/user",
+      "pages": [
+        {
+          "path": "info",
+          "style": {
+            "navigationBarTitleText": "我的信息"
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "用户信息",
+            "group": "用户中心"
+          }
+        },
+        {
+          "path": "goods-collect",
+          "style": {
+            "navigationBarTitleText": "我的收藏"
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "商品收藏",
+            "group": "用户中心"
+          }
+        },
+        {
+          "path": "goods-log",
+          "style": {
+            "navigationBarTitleText": "我的足迹"
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "浏览记录",
+            "group": "用户中心"
+          }
+        },
+        {
+          "path": "address/list",
+          "style": {
+            "navigationBarTitleText": "收货地址"
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "地址管理",
+            "group": "用户中心"
+          }
+        },
+        {
+          "path": "address/edit",
+          "style": {
+            "navigationBarTitleText": "编辑地址"
+          },
+          "meta": {
+            "auth": true,
+            "title": "编辑地址"
+          }
+        },
+        {
+          "path": "goods_details_store/index",
+          "style": {
+            "navigationBarTitleText": "自提门店"
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "地址管理",
+            "group": "用户中心"
+          }
+        },
+        {
+          "path": "wallet/money",
+          "style": {
+            "navigationBarTitleText": "我的余额"
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "用户余额",
+            "group": "用户中心"
+          }
+        },
+        {
+          "path": "wallet/score",
+          "style": {
+            "navigationBarTitleText": "我的积分"
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "用户积分",
+            "group": "用户中心"
+          }
+        }
+      ]
+    },
+    {
+      "root": "pages/commission",
+      "pages": [
+        {
+          "path": "index",
+          "style": {
+            "navigationBarTitleText": "分销"
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "分销中心",
+            "group": "分销商城"
+          }
+        },
+        {
+          "path": "wallet",
+          "style": {
+            "navigationBarTitleText": "我的佣金"
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "用户佣金",
+            "group": "分销中心"
+          }
+        },
+        {
+          "path": "goods",
+          "style": {
+            "navigationBarTitleText": "推广商品"
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "推广商品",
+            "group": "分销商城"
+          }
+        },
+        {
+          "path": "order",
+          "style": {
+            "navigationBarTitleText": "分销订单"
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "分销订单",
+            "group": "分销商城"
+          }
+        },
+        {
+          "path": "team",
+          "style": {
+            "navigationBarTitleText": "我的团队"
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "我的团队",
+            "group": "分销商城"
+          }
+        },
+        {
+          "path": "promoter",
+          "style": {
+            "navigationBarTitleText": "推广人排行榜"
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "推广人排行榜",
+            "group": "分销商城"
+          }
+        },
+        {
+          "path": "commission-ranking",
+          "style": {
+            "navigationBarTitleText": "佣金排行榜"
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "佣金排行榜",
+            "group": "分销商城"
+          }
+        },
+        {
+          "path": "withdraw",
+          "style": {
+            "navigationBarTitleText": "申请提现"
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "申请提现",
+            "group": "分销商城"
+          }
+        }
+      ]
+    },
+    {
+      "root": "pages/app",
+      "pages": [
+        {
+          "path": "sign",
+          "style": {
+            "navigationBarTitleText": "签到中心"
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "签到中心",
+            "group": "应用"
+          }
+        }
+      ]
+    },
+    {
+      "root": "pages/public",
+      "pages": [
+        {
+          "path": "setting",
+          "style": {
+            "navigationBarTitleText": "系统设置"
+          },
+          "meta": {
+            "sync": true,
+            "title": "系统设置",
+            "group": "通用"
+          }
+        },
+        {
+          "path": "richtext",
+          "style": {
+            "navigationBarTitleText": "富文本"
+          },
+          "meta": {
+            "sync": true,
+            "title": "富文本",
+            "group": "通用"
+          }
+        },
+        {
+          "path": "faq",
+          "style": {
+            "navigationBarTitleText": "常见问题"
+          },
+          "meta": {
+            "sync": true,
+            "title": "常见问题",
+            "group": "通用"
+          }
+        },
+        {
+          "path": "error",
+          "style": {
+            "navigationBarTitleText": "错误页面"
+          }
+        },
+        {
+          "path": "webview",
+          "style": {
+            "navigationBarTitleText": ""
+          }
+        }
+      ]
+    },
+    {
+      "root": "pages/coupon",
+      "pages": [
+        {
+          "path": "list",
+          "style": {
+            "navigationBarTitleText": "领券中心"
+          },
+          "meta": {
+            "sync": true,
+            "title": "领券中心",
+            "group": "优惠券"
+          }
+        },
+        {
+          "path": "detail",
+          "style": {
+            "navigationBarTitleText": "优惠券"
+          },
+          "meta": {
+            "auth": false,
+            "sync": true,
+            "title": "优惠券详情",
+            "group": "优惠券"
+          }
+        }
+      ]
+    },
+    {
+      "root": "pages/chat",
+      "pages": [
+        {
+          "path": "index",
+          "style": {
+            "navigationBarTitleText": "客服"
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "客服",
+            "group": "客服"
+          }
+        }
+      ]
+    },
+    {
+      "root": "pages/pay",
+      "pages": [
+        {
+          "path": "index",
+          "style": {
+            "navigationBarTitleText": "收银台"
+          }
+        },
+        {
+          "path": "result",
+          "style": {
+            "navigationBarTitleText": "支付结果"
+          }
+        },
+        {
+          "path": "recharge",
+          "style": {
+            "navigationBarTitleText": "充值余额"
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "充值余额",
+            "group": "支付"
+          }
+        },
+        {
+          "path": "recharge-log",
+          "style": {
+            "navigationBarTitleText": "充值记录"
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "充值记录",
+            "group": "支付"
+          }
+        }
+      ]
+    },
+    {
+      "root": "pages/activity",
+      "pages": [
+        {
+          "path": "groupon/detail",
+          "style": {
+            "navigationBarTitleText": "拼团详情"
+          }
+        },
+        {
+          "path": "groupon/order",
+          "style": {
+            "navigationBarTitleText": "我的拼团",
+            "enablePullDownRefresh": true
+          },
+          "meta": {
+            "auth": true,
+            "sync": true,
+            "title": "拼团订单",
+            "group": "营销活动"
+          }
+        },
+        {
+          "path": "index",
+          "style": {
+            "navigationBarTitleText": "营销商品"
+          },
+          "meta": {
+            "sync": true,
+            "title": "营销商品",
+            "group": "营销活动"
+          }
+        },
+        {
+          "path": "groupon/list",
+          "style": {
+            "navigationBarTitleText": "拼团活动"
+          },
+          "meta": {
+            "sync": true,
+            "title": "拼团活动",
+            "group": "营销活动"
+          }
+        },
+        {
+          "path": "seckill/list",
+          "style": {
+            "navigationBarTitleText": "秒杀活动"
+          },
+          "meta": {
+            "sync": true,
+            "title": "秒杀活动",
+            "group": "营销活动"
+          }
+        }
+      ]
+    }
+  ],
+  "globalStyle": {
+    "navigationBarTextStyle": "black",
+    "navigationBarTitleText": "芋道商城",
+    "navigationBarBackgroundColor": "#FFFFFF",
+    "backgroundColor": "#FFFFFF",
+    "navigationStyle": "custom"
+  },
+  "tabBar": {
+    "list": [
+      {
+        "pagePath": "pages/index/index"
+      },
+      {
+        "pagePath": "pages/index/cart"
+      },
+      {
+        "pagePath": "pages/index/user"
+      }
+    ]
+  }
 }

+ 10 - 2
pages/activity/index.vue

@@ -7,7 +7,7 @@
         <view class="type-text ss-flex ss-row-center">满减:</view>
         <view class="ss-flex-1">
           <view class="tip-content" v-for="item in state.activityInfo.rules" :key="item">
-            {{ formatRewardActivityRule(state.activityInfo, item) }}
+            {{ item.description }}
           </view>
         </view>
         <image class="activity-left-image" src="/static/activity-left.png" />
@@ -65,8 +65,9 @@
   import sheep from '@/sheep';
   import _ from 'lodash-es';
   import RewardActivityApi from '@/sheep/api/promotion/rewardActivity';
-  import { formatRewardActivityRule } from '@/sheep/hooks/useGoods';
   import SpuApi from '@/sheep/api/product/spu';
+  import { appendSettlementProduct } from '@/sheep/hooks/useGoods';
+  import OrderApi from '@/sheep/api/trade/order';
 
   const state = reactive({
     activityId: 0, // 获得编号
@@ -123,6 +124,13 @@
     if (code !== 0) {
       return;
     }
+    // 拼接结算信息(营销)
+    await OrderApi.getSettlementProduct(data.list.map((item) => item.id).join(',')).then((res) => {
+      if (res.code !== 0) {
+        return;
+      }
+      appendSettlementProduct(data.list, res.data);
+    });
     state.pagination.list = _.concat(state.pagination.list, data.list);
     state.pagination.total = data.total;
     state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';

+ 78 - 0
pages/activity/point/list.vue

@@ -0,0 +1,78 @@
+<!-- 积分商城:商品列表  -->
+<template>
+  <s-layout title="积分商城">
+    <view class="ss-p-20">
+      <view v-for="item in state.pagination.data" :key="item.id" class="ss-m-b-20">
+        <s-point-card
+          size="sl"
+          :data="item"
+          priceColor="#FF3000"
+          @tap="sheep.$router.go('/pages/goods/point', { id: item.id })"
+        />
+      </view>
+    </view>
+    <s-empty
+      v-if="state.pagination.total === 0"
+      icon="/static/goods-empty.png"
+      text="暂无积分商品"
+    />
+    <uni-load-more
+      v-if="state.pagination.total > 0"
+      :status="state.loadStatus"
+      :content-text="{
+        contentdown: '上拉加载更多',
+      }"
+      @tap="loadmore"
+    />
+  </s-layout>
+</template>
+<script setup>
+  import sheep from '@/sheep';
+  import { onLoad, onReachBottom } from '@dcloudio/uni-app';
+  import { reactive } from 'vue';
+  import _ from 'lodash';
+
+  const state = reactive({
+    pagination: {
+      data: [],
+      current_page: 1,
+      total: 1,
+      last_page: 1,
+    },
+    loadStatus: '',
+  });
+  async function getData(page = 1, list_rows = 5) {
+    // TODO @puhui999:分页重写成,我们的代码风格。原先的有点复杂
+    state.loadStatus = 'loading';
+    let res = await sheep.$api.app.scoreShop.list({
+      list_rows,
+      page,
+    });
+    if (res.error === 0) {
+      let couponlist = _.concat(state.pagination.data, res.data.data);
+      state.pagination = {
+        ...res.data,
+        data: couponlist,
+      };
+      if (state.pagination.current_page < state.pagination.last_page) {
+        state.loadStatus = 'more';
+      } else {
+        state.loadStatus = 'noMore';
+      }
+    }
+  }
+  // 加载更多
+  function loadmore() {
+    if (state.loadStatus !== 'noMore') {
+      getData(state.pagination.current_page + 1);
+    }
+  }
+
+  // 上拉加载更多
+  onReachBottom(() => {
+    loadmore();
+  });
+  onLoad(() => {
+    getData();
+  });
+</script>

+ 137 - 61
pages/activity/seckill/list.vue

@@ -3,13 +3,20 @@
   <s-layout navbar="inner" :bgStyle="{ color: 'rgb(245,28,19)' }">
     <!--顶部背景图-->
     <view
-        class="page-bg"
-        :style="[{ marginTop: '-' + Number(statusBarHeight + 88) + 'rpx' }]"
+      class="page-bg"
+      :style="[{ marginTop: '-' + Number(statusBarHeight + 88) + 'rpx' }]"
     ></view>
     <!-- 时间段轮播图 -->
     <view class="header" v-if="activeTimeConfig?.sliderPicUrls?.length > 0">
-      <swiper indicator-dots="true" autoplay="true" :circular="true" interval="3000" duration="1500"
-              indicator-color="rgba(255,255,255,0.6)" indicator-active-color="#fff">
+      <swiper
+        indicator-dots="true"
+        autoplay="true"
+        :circular="true"
+        interval="3000"
+        duration="1500"
+        indicator-color="rgba(255,255,255,0.6)"
+        indicator-active-color="#fff"
+      >
         <block v-for="(picUrl, index) in activeTimeConfig.sliderPicUrls" :key="index">
           <swiper-item class="borRadius14">
             <image :src="picUrl" class="slide-image borRadius14" lazy-load />
@@ -22,17 +29,28 @@
       <!-- 左侧图标 -->
       <view class="time-icon">
         <!-- TODO 芋艿:图片统一维护 -->
-        <image class="ss-w-100 ss-h-100" src="http://mall.yudao.iocoder.cn/static/images/priceTag.png" />
+        <image
+          class="ss-w-100 ss-h-100"
+          src="http://mall.yudao.iocoder.cn/static/images/priceTag.png"
+        />
       </view>
-      <scroll-view class="time-list" :scroll-into-view="activeTimeElId" scroll-x scroll-with-animation>
-        <view v-for="(config, index) in timeConfigList" :key="index"
-              :class="['item', { active: activeTimeIndex === index}]"
-              :id="`timeItem${index}`"
-              @tap="handleChangeTimeConfig(index)">
+      <scroll-view
+        class="time-list"
+        :scroll-into-view="activeTimeElId"
+        scroll-x
+        scroll-with-animation
+      >
+        <view
+          v-for="(config, index) in timeConfigList"
+          :key="index"
+          :class="['item', { active: activeTimeIndex === index }]"
+          :id="`timeItem${index}`"
+          @tap="handleChangeTimeConfig(index, config.id)"
+        >
           <!-- 活动起始时间 -->
           <view class="time">{{ config.startTime }}</view>
           <!-- 活动状态 -->
-          <view class="status">{{ config.status }}</view>
+          <view class="status">{{ config?.status }}</view>
         </view>
       </scroll-view>
     </view>
@@ -42,7 +60,10 @@
       <!-- 活动倒计时 -->
       <view class="content-header ss-flex-col ss-col-center ss-row-center">
         <view class="content-header-box ss-flex ss-row-center">
-          <view class="countdown-box ss-flex" v-if="activeTimeConfig?.status === TimeStatusEnum.STARTED">
+          <view
+            class="countdown-box ss-flex"
+            v-if="activeTimeConfig?.status === TimeStatusEnum.STARTED"
+          >
             <view class="countdown-title ss-m-r-12">距结束</view>
             <view class="ss-flex countdown-time">
               <view class="ss-flex countdown-h">{{ countDown.h }}</view>
@@ -70,19 +91,44 @@
             :data="{ ...activity, price: activity.seckillPrice }"
             :goodsFields="goodsFields"
             :seckillTag="true"
-            @click="sheep.$router.go('/pages/goods/seckill', { id: activity.id })"
           >
             <!-- 抢购进度 -->
             <template #activity>
-              <view class="limit">限量 <text class="ss-m-l-5">{{ activity.stock}} {{activity.unitName}}</text></view>
+              <view class="limit">
+                限量
+                <text class="ss-m-l-5">{{ activity.stock }} {{ activity.unitName }}</text>
+              </view>
               <su-progress :percentage="activity.percent" strokeWidth="10" textInside isAnimate />
             </template>
             <!-- 抢购按钮 -->
             <template #cart>
-              <button :class="['ss-reset-button cart-btn', { disabled: activeTimeConfig.status === TimeStatusEnum.END }]">
-                <span v-if="activeTimeConfig?.status === TimeStatusEnum.WAIT_START">未开始</span>
-                <span v-else-if="activeTimeConfig?.status === TimeStatusEnum.STARTED">马上抢</span>
-                <span v-else>已结束</span>
+              <button
+                :class="[
+                  'ss-reset-button cart-btn',
+                  { disabled: activeTimeConfig?.status === TimeStatusEnum.END },
+                ]"
+                v-if="activeTimeConfig?.status === TimeStatusEnum.WAIT_START"
+              >
+                <span>未开始</span>
+              </button>
+              <button
+                :class="[
+                  'ss-reset-button cart-btn',
+                  { disabled: activeTimeConfig?.status === TimeStatusEnum.END },
+                ]"
+                @click="sheep.$router.go('/pages/goods/seckill', { id: activity.id })"
+                v-else-if="activeTimeConfig?.status === TimeStatusEnum.STARTED"
+              >
+                <span>马上抢</span>
+              </button>
+              <button
+                :class="[
+                  'ss-reset-button cart-btn',
+                  { disabled: activeTimeConfig?.status === TimeStatusEnum.END },
+                ]"
+                v-else
+              >
+                <span>已结束</span>
               </button>
             </template>
           </s-goods-column>
@@ -100,40 +146,51 @@
   </s-layout>
 </template>
 <script setup>
-  import {reactive, computed, ref, nextTick} from 'vue';
+  import { reactive, computed, ref, nextTick } from 'vue';
   import { onLoad, onReachBottom } from '@dcloudio/uni-app';
   import sheep from '@/sheep';
   import { useDurationTime } from '@/sheep/hooks/useGoods';
-  import SeckillApi from "@/sheep/api/promotion/seckill";
-  import dayjs from "dayjs";
-  import {TimeStatusEnum} from "@/sheep/util/const";
+  import SeckillApi from '@/sheep/api/promotion/seckill';
+  import dayjs from 'dayjs';
+  import { TimeStatusEnum } from '@/sheep/util/const';
 
   // 计算页面高度
   const { safeAreaInsets, safeArea } = sheep.$platform.device;
   const statusBarHeight = sheep.$platform.device.statusBarHeight * 2;
-  const pageHeight = (safeArea.height + safeAreaInsets.bottom) * 2 + statusBarHeight - sheep.$platform.navbar - 350;
+  const pageHeight =
+    (safeArea.height + safeAreaInsets.bottom) * 2 + statusBarHeight - sheep.$platform.navbar - 350;
   const headerBg = sheep.$url.css('/static/img/shop/goods/seckill-header.png');
 
   // 商品控件显示的字段(不显示库存、销量。改为显示自定义的进度条)
   const goodsFields = {
-    name: { show: true },
-    introduction: { show: true },
-    price: { show: true },
-    marketPrice: { show: true },
+    name: {
+      show: true,
+    },
+    introduction: {
+      show: true,
+    },
+    price: {
+      show: true,
+    },
+    marketPrice: {
+      show: true,
+    },
   };
 
   //#region 时间段
   // 时间段列表
-  const timeConfigList = ref([])
+  const timeConfigList = ref([]);
   // 查询时间段
   const getSeckillConfigList = async () => {
-    const { data } = await SeckillApi.getSeckillConfigList()
+    const { data } = await SeckillApi.getSeckillConfigList();
     const now = dayjs();
-    const today = now.format('YYYY-MM-DD')
+    const today = now.format('YYYY-MM-DD');
+    const select = ref([]);
     // 判断时间段的状态
     data.forEach((config, index) => {
-      const startTime = dayjs(`${today} ${config.startTime}`)
-      const endTime = dayjs(`${today} ${config.endTime}`)
+      const startTime = dayjs(`${today} ${config.startTime}`);
+      const endTime = dayjs(`${today} ${config.endTime}`);
+      select.value[index] = config.id;
       if (now.isBefore(startTime)) {
         config.status = TimeStatusEnum.WAIT_START;
       } else if (now.isAfter(endTime)) {
@@ -142,35 +199,36 @@
         config.status = TimeStatusEnum.STARTED;
         activeTimeIndex.value = index;
       }
-    })
-    timeConfigList.value = data
+    });
+    timeConfigList.value = data;
     // 默认选中进行中的活动
-    handleChangeTimeConfig(activeTimeIndex.value);
+    handleChangeTimeConfig(activeTimeIndex.value, select.value[activeTimeIndex.value]);
     // 滚动到进行中的时间段
-    scrollToTimeConfig(activeTimeIndex.value)
-  }
+    scrollToTimeConfig(activeTimeIndex.value);
+  };
 
   // 滚动到指定时间段
-  const activeTimeElId = ref('') // 当前选中的时间段的元素ID
+  const activeTimeElId = ref(''); // 当前选中的时间段的元素ID
   const scrollToTimeConfig = (index) => {
-    nextTick(() => activeTimeElId.value = `timeItem${index}`)
-  }
+    nextTick(() => (activeTimeElId.value = `timeItem${index}`));
+  };
 
   // 切换时间段
-  const activeTimeIndex = ref(0) // 当前选中的时间段的索引
-  const activeTimeConfig = computed(() => timeConfigList.value[activeTimeIndex.value]) // 当前选中的时间段
-  const handleChangeTimeConfig = (index) => {
-    activeTimeIndex.value = index
+  const activeTimeIndex = ref(0); // 当前选中的时间段的索引
+  const activeTimeConfig = computed(() => timeConfigList.value[activeTimeIndex.value]); // 当前选中的时间段
+  const handleChangeTimeConfig = (index, id) => {
+    activeTimeIndex.value = index;
 
     // 查询活动列表
-    activityPageParams.pageNo = 1
-    activityList.value = []
+    activityPageParams.pageNo = 1;
+    activityPageParams.configId = id;
+    activityList.value = [];
     getActivityList();
-  }
+  };
 
   // 倒计时
   const countDown = computed(() => {
-    const endTime = activeTimeConfig.value?.endTime
+    const endTime = activeTimeConfig.value?.endTime;
     if (endTime) {
       return useDurationTime(`${dayjs().format('YYYY-MM-DD')} ${endTime}`);
     }
@@ -182,20 +240,22 @@
 
   // 查询活动列表
   const activityPageParams = reactive({
-    id: 0, // 时间段 ID
+    configId: 0, // 时间段 ID
     pageNo: 1, // 页码
     pageSize: 5, // 每页数量
-  })
-  const activityTotal = ref(0) // 活动总数
-  const activityList = ref([]) // 活动列表
-  const loadStatus = ref('') // 页面加载状态
+  });
+  const activityTotal = ref(0); // 活动总数
+  const activityList = ref([]); // 活动列表
+  const loadStatus = ref(''); // 页面加载状态
   async function getActivityList() {
     loadStatus.value = 'loading';
-    const { data } = await SeckillApi.getSeckillActivityPage(activityPageParams)
-    data.list.forEach(activity => {
+    const { data } = await SeckillApi.getSeckillActivityPage(activityPageParams);
+    data.list.forEach((activity) => {
       // 计算抢购进度
-      activity.percent = parseInt(100 * (activity.totalStock - activity.stock) / activity.totalStock);
-    })
+      activity.percent = parseInt(
+        (100 * (activity.totalStock - activity.stock)) / activity.totalStock,
+      );
+    });
     activityList.value = activityList.value.concat(...data.list);
     activityTotal.value = data.total;
 
@@ -205,7 +265,7 @@
   // 加载更多
   function loadMore() {
     if (loadStatus.value !== 'noMore') {
-      activityPageParams.pageNo += 1
+      activityPageParams.pageNo += 1;
       getActivityList();
     }
   }
@@ -216,7 +276,7 @@
 
   // 页面初始化
   onLoad(async () => {
-    await getSeckillConfigList()
+    await getSeckillConfigList();
   });
 </script>
 <style lang="scss" scoped>
@@ -235,7 +295,8 @@
     margin: -276rpx auto 0 auto;
     border-radius: 14rpx;
     overflow: hidden;
-    swiper{
+
+    swiper {
       height: 330rpx !important;
       border-radius: 14rpx;
       overflow: hidden;
@@ -246,7 +307,8 @@
       height: 100%;
       border-radius: 14rpx;
       overflow: hidden;
-      img{
+
+      img {
         border-radius: 14rpx;
       }
     }
@@ -257,10 +319,12 @@
     width: 75rpx;
     height: 70rpx;
   }
+
   // 时间段列表
   .time-list {
     width: 596rpx;
     white-space: nowrap;
+
     // 时间段
     .item {
       display: inline-block;
@@ -270,17 +334,20 @@
       box-sizing: border-box;
       margin-right: 30rpx;
       width: 130rpx;
+
       // 开始时间
       .time {
         font-size: 36rpx;
         font-weight: 600;
         color: #333;
       }
+
       // 选中的时间段
       &.active {
         .time {
           color: var(--ui-BG-Main);
         }
+
         // 状态
         .status {
           height: 30rpx;
@@ -301,6 +368,7 @@
     margin: 0 20rpx 0 20rpx;
     background: #fff;
     border-radius: 20rpx 20rpx 0 0;
+
     .content-header {
       width: 100%;
       border-radius: 20rpx 20rpx 0 0;
@@ -312,6 +380,7 @@
         height: 64rpx;
         background: rgba($color: #fff, $alpha: 0.66);
         border-radius: 32px;
+
         // 场次倒计时内容
         .countdown-title {
           font-size: 28rpx;
@@ -319,10 +388,12 @@
           color: #333333;
           line-height: 28rpx;
         }
+
         // 场次倒计时
         .countdown-time {
           font-size: 28rpx;
           color: rgba(#ed3c30, 0.23);
+
           // 场次倒计时:小时部分
           .countdown-h {
             font-size: 24rpx;
@@ -334,6 +405,7 @@
             background: rgba(#ed3c30, 0.23);
             border-radius: 6rpx;
           }
+
           // 场次倒计时:分钟、秒
           .countdown-num {
             font-size: 24rpx;
@@ -348,12 +420,15 @@
         }
       }
     }
+
     // 活动列表
     .scroll-box {
       height: 900rpx;
+
       // 活动
       .goods-box {
         position: relative;
+
         // 抢购按钮
         .cart-btn {
           position: absolute;
@@ -373,6 +448,7 @@
             color: #fff;
           }
         }
+
         // 秒杀限量商品数
         .limit {
           font-size: 22rpx;

+ 1 - 1
pages/coupon/detail.vue

@@ -36,7 +36,7 @@
               <text v-else>
                 {{
                   state.coupon.status === 1
-                    ? '立即使用'
+                    ? '使用'
                     : state.coupon.status === 2
                     ? '已使用'
                     : '已过期'

+ 1 - 1
pages/goods/comment/add.vue

@@ -121,7 +121,7 @@
     }
     state.id = options.id;
 
-    const { code, data } = await OrderApi.getOrder(state.id);
+    const { code, data } = await OrderApi.getOrderDetail(state.id);
     if (code !== 0) {
       sheep.$helper.toast('无待评价订单');
       return;

+ 249 - 31
pages/goods/index.vue

@@ -27,10 +27,60 @@
             dotCur="bg-mask-40"
             :seizeHeight="750"
           />
-
+          <!-- 限时折扣/会员价的优惠信息 -->
+          <view
+            class="discount"
+            v-if="
+              state.settlementSku && state.settlementSku.id && state.settlementSku.promotionPrice
+            "
+          >
+            <image class="disImg" :src="sheep.$url.static('/static/img/shop/goods/dis.png')" />
+            <view class="discountCont">
+              <view class="disContT">
+                <view class="disContT1">
+                  <view class="disContT1P">
+                    ¥{{ fen2yuan(state.settlementSku.promotionPrice) }}
+                  </view>
+                  <view class="disContT1End">
+                    直降¥
+                    {{ fen2yuan(state.settlementSku.price - state.settlementSku.promotionPrice) }}
+                  </view>
+                </view>
+                <view class="disContT2" v-if="state.settlementSku.promotionType === 4">
+                  限时折扣
+                </view>
+                <view class="disContT2" v-else-if="state.settlementSku.promotionType === 6">
+                  会员折扣
+                </view>
+              </view>
+              <view class="disContB">
+                <view class="disContB1">
+                  价格:¥{{ fen2yuan(state.settlementSku.price) }} 丨 剩余:
+                  {{ state.settlementSku.stock }}
+                </view>
+                <view class="disContB2" v-if="state.settlementSku.promotionEndTime > 0">
+                  距结束仅剩
+                  <countDown
+                    :tipText="' '"
+                    :bgColor="bgColor"
+                    :dayText="':'"
+                    :hourText="':'"
+                    :minuteText="':'"
+                    :secondText="' '"
+                    :datatime="state.settlementSku.promotionEndTime / 1000"
+                    :isDay="false"
+                  />
+                </view>
+              </view>
+            </view>
+          </view>
           <!-- 价格+标题 -->
-          <view class="title-card detail-card ss-p-y-40 ss-p-x-20">
-            <view class="ss-flex ss-row-between ss-col-center ss-m-b-26">
+          <view class="title-card detail-card ss-p-y-30 ss-p-x-20">
+            <!-- 没有限时折扣/会员价的优惠信息时,展示的价格信息 -->
+            <view
+              class="ss-flex ss-row-between ss-col-center ss-m-b-26"
+              v-if="!state.settlementSku.promotionPrice"
+            >
               <view class="price-box ss-flex ss-col-bottom">
                 <view class="price-text ss-m-r-16">
                   {{ fen2yuan(state.selectedSku.price || state.goodsInfo.price) }}
@@ -44,24 +94,39 @@
               </view>
             </view>
             <view class="discounts-box ss-flex ss-row-between ss-m-b-28">
-              <!-- 满减送/限时折扣活动的提示 -->
+              <!-- 查看优惠劵的描述 -->
+              <view
+                class="tag ss-m-r-10"
+                v-for="coupon in state.couponInfo.slice(0, 1)"
+                :key="coupon.id"
+                @tap="onOpenActivity"
+              >
+                [劵]满{{ fen2yuanSimple(coupon.usePrice) }}元{{
+                  coupon.discountType === 1
+                    ? '减' + fen2yuanSimple(coupon.discountPrice) + '元'
+                    : '打' + formatDiscountPercent(coupon.discountPercent) + '折'
+                }}
+              </view>
+              <!-- 查看满减送的描述 -->
               <div class="tag-content">
                 <view class="tag-box ss-flex">
+                  <!-- 最多打印 3 条,所以需要扣除优惠劵已打印的 -->
                   <view
+                    v-for="item in getRewardActivityRuleItemDescriptions(
+                      state.rewardActivity,
+                    ).slice(0, 3 - state.couponInfo.slice(0, 1).length)"
+                    :key="item"
                     class="tag ss-m-r-10"
-                    v-for="promos in state.activityInfo"
-                    :key="promos.id"
-                    @tap="onActivity"
+                    @tap="onOpenActivity"
                   >
-                    {{ promos.name }}
+                    <text>{{ item }}</text>
                   </view>
                 </view>
               </div>
-
-              <!-- 优惠劵 -->
+              <!-- 领取优惠劵的按钮 -->
               <view
                 class="get-coupon-box ss-flex ss-col-center ss-m-l-20"
-                @tap="state.showModel = true"
+                @tap="onOpenActivity"
                 v-if="state.couponInfo.length"
               >
                 <view class="discounts-title ss-m-r-8">领券</view>
@@ -127,19 +192,12 @@
           </view>
         </detail-tabbar>
 
-        <!-- 优惠劵弹窗 -->
-        <s-coupon-get
-          v-model="state.couponInfo"
-          :show="state.showModel"
-          @close="state.showModel = false"
-          @get="onGet"
-        />
-
         <!-- 满减送/限时折扣活动弹窗 -->
         <s-activity-pop
-          v-model="state.activityInfo"
+          v-model="state"
           :show="state.showActivityModel"
           @close="state.showActivityModel = false"
+          @get="onTakeCoupon"
         />
       </block>
     </s-layout>
@@ -147,13 +205,21 @@
 </template>
 
 <script setup>
-  import { reactive, computed } from 'vue';
+  import { reactive, computed, ref, toRaw } from 'vue';
   import { onLoad, onPageScroll } from '@dcloudio/uni-app';
   import sheep from '@/sheep';
   import CouponApi from '@/sheep/api/promotion/coupon';
   import ActivityApi from '@/sheep/api/promotion/activity';
   import FavoriteApi from '@/sheep/api/product/favorite';
-  import { formatSales, formatGoodsSwiper, fen2yuan } from '@/sheep/hooks/useGoods';
+  import RewardActivityApi from '@/sheep/api/promotion/rewardActivity';
+  import {
+    formatSales,
+    formatGoodsSwiper,
+    fen2yuan,
+    fen2yuanSimple,
+    formatDiscountPercent,
+    getRewardActivityRuleItemDescriptions,
+  } from '@/sheep/hooks/useGoods';
   import detailNavbar from './components/detail/detail-navbar.vue';
   import detailCellSku from './components/detail/detail-cell-sku.vue';
   import detailTabbar from './components/detail/detail-tabbar.vue';
@@ -165,7 +231,17 @@
   import SpuApi from '@/sheep/api/product/spu';
 
   onPageScroll(() => {});
-
+  import countDown from '@/sheep/components/countDown/index.vue';
+  import OrderApi from '@/sheep/api/trade/order';
+  import activity from '@/sheep/api/promotion/activity';
+
+  const bgColor = {
+    bgColor: '#E93323',
+    Color: '#fff',
+    width: '44rpx',
+    timeTxtwidth: '16rpx',
+    isDay: true,
+  };
   const isLogin = computed(() => sheep.$store('user').isLogin);
   const state = reactive({
     goodsId: 0,
@@ -173,16 +249,18 @@
     goodsInfo: {}, // SPU 信息
     showSelectSku: false, // 是否展示 SKU 选择弹窗
     selectedSku: {}, // 选中的 SKU
+    settlementSku: {}, // 结算的 SKU:由于 selectedSku 不进行默认选中,所以初始使用结算价格最低的 SKU 作为基础展示
     showModel: false, // 是否展示 Coupon 优惠劵的弹窗
     couponInfo: [], // 可领取的 Coupon 优惠劵的列表
     showActivityModel: false, // 【满减送/限时折扣】是否展示 Activity 营销活动的弹窗
-    activityInfo: [], // 【满减送/限时折扣】可参与的 Activity 营销活动的列表 TODO 芋艿:正在接入中
+    rewardActivity: {}, // 【满减送】活动
     activityList: [], // 【秒杀/拼团/砍价】可参与的 Activity 营销活动的列表
   });
 
   // 规格变更
   function onSkuChange(e) {
     state.selectedSku = e;
+    state.settlementSku = e;
   }
 
   // 添加购物车
@@ -196,7 +274,7 @@
 
   // 立即购买
   function onBuy(e) {
-    if (!state.selectedSku.id) {
+    if (!e.id) {
       sheep.$helper.toast('请选择商品规格');
       return;
     }
@@ -213,13 +291,13 @@
     });
   }
 
-  // 营销活动
-  function onActivity() {
+  // 打开营销弹窗
+  function onOpenActivity() {
     state.showActivityModel = true;
   }
 
-  // 立即领取
-  async function onGet(id) {
+  // 立即领取优惠劵
+  async function onTakeCoupon(id) {
     const { code } = await CouponApi.takeCoupon(id);
     if (code !== 0) {
       return;
@@ -261,6 +339,48 @@
     }
   }
 
+  async function getSettlementByIds(ids) {
+    let { data, code } = await OrderApi.getSettlementProduct(ids);
+    if (code !== 0 || data.length !== 1) {
+      return;
+    }
+    data = data[0];
+
+    // 补充 SKU 的价格信息
+    state.goodsInfo.skus.forEach((sku) => {
+      data.skus.forEach((item) => {
+        if (sku.id === item.id) {
+          sku.promotionType = item.promotionType;
+          sku.promotionPrice = item.promotionPrice;
+          sku.promotionId = item.promotionId;
+          sku.promotionEndTime = item.promotionEndTime;
+        }
+      });
+    });
+
+    // 选择有 promotionPrice 且最小的
+    state.settlementSku = state.goodsInfo.skus
+      .filter((sku) => sku.stock > 0 && sku.promotionPrice > 0)
+      .reduce((prev, curr) => (prev.promotionPrice < curr.promotionPrice ? prev : curr));
+
+    // 设置满减送活动
+    if (data.rewardActivity) {
+      state.rewardActivity = data.rewardActivity;
+      //获取活动时间
+      getActivityTime(state.rewardActivity.id);
+    }
+  }
+
+  //获取活动时间
+  async function getActivityTime(id) {
+    const { code, data } = await RewardActivityApi.getRewardActivity(id);
+    if (code === 0) {
+      // console.log('获取到的活动 数据', data)
+      state.rewardActivity.startTime = data.startTime;
+      state.rewardActivity.endTime = data.endTime;
+    }
+  }
+
   onLoad((options) => {
     // 非法参数
     if (!options.id) {
@@ -278,7 +398,6 @@
       // 加载到商品
       state.skeletonLoading = false;
       state.goodsInfo = res.data;
-
       // 加载是否收藏
       if (isLogin.value) {
         FavoriteApi.isFavoriteExists(state.goodsId, 'goods').then((res) => {
@@ -293,13 +412,15 @@
     // 2. 加载优惠劵信息
     getCoupon();
 
-    // 3. 获得单个商品,进行中的拼团、秒杀、砍价活动信息
+    // 3. 加载营销活动信息
     ActivityApi.getActivityListBySpuId(state.goodsId).then((res) => {
       if (res.code !== 0) {
         return;
       }
       state.activityList = res.data;
     });
+    //获取结算信息
+    getSettlementByIds(state.goodsId);
   });
 </script>
 
@@ -448,4 +569,101 @@
       color: #333333;
     }
   }
+
+  // 限时折扣
+  .discount {
+    width: 750rpx;
+    height: 100rpx;
+    // background-color: red;
+    overflow: hidden;
+    position: relative;
+  }
+
+  .disImg {
+    width: 750rpx;
+    height: 100rpx;
+    position: absolute;
+    top: 0;
+    z-index: -1;
+  }
+
+  .discountCont {
+    width: 680rpx;
+    height: 90rpx;
+    margin: 10rpx auto 0 auto;
+    // background-color: gold;
+  }
+
+  .disContT {
+    width: 680rpx;
+    height: 50rpx;
+    display: flex;
+    justify-content: space-between;
+  }
+
+  .disContT1 {
+    width: 400rpx;
+    height: 50rpx;
+    // background-color: green;
+    display: flex;
+    justify-content: flex-start;
+    align-items: center;
+  }
+
+  .disContT2 {
+    width: 200rpx;
+    height: 50rpx;
+    line-height: 50rpx;
+    // background-color: gold;
+    font-size: 30rpx;
+    text-align: end;
+    color: white;
+    font-weight: bolder;
+    font-style: oblique 20deg;
+    letter-spacing: 0.1rem;
+  }
+
+  .disContT1P {
+    color: white;
+    font-weight: bold;
+    font-size: 28rpx;
+  }
+
+  .disContT1End {
+    // width: 180rpx;
+    padding: 0 10rpx;
+    height: 30rpx;
+    line-height: 28rpx;
+    text-align: center;
+    font-weight: bold;
+    background-color: white;
+    color: #ff3000;
+    font-size: 23rpx;
+    border-radius: 20rpx;
+    margin-left: 10rpx;
+  }
+
+  .disContB {
+    width: 680rpx;
+    height: 40rpx;
+    display: flex;
+    justify-content: space-between;
+    font-size: 20rpx;
+    color: white;
+    align-items: center;
+  }
+
+  .disContB1 {
+    width: 300rpx;
+    height: 40rpx;
+    line-height: 40rpx;
+  }
+
+  .disContB2 {
+    width: 300rpx;
+    height: 40rpx;
+    line-height: 40rpx;
+    display: flex;
+    justify-content: flex-end;
+  }
 </style>

+ 10 - 1
pages/goods/list.vue

@@ -118,12 +118,14 @@
 </template>
 
 <script setup>
-  import { reactive } from 'vue';
+  import { reactive, ref } from 'vue';
   import { onLoad, onReachBottom } from '@dcloudio/uni-app';
   import sheep from '@/sheep';
   import _ from 'lodash-es';
   import { resetPagination } from '@/sheep/util';
   import SpuApi from '@/sheep/api/product/spu';
+  import OrderApi from '@/sheep/api/trade/order';
+  import { appendSettlementProduct } from '@/sheep/hooks/useGoods';
 
   const sys_navBar = sheep.$platform.navbar;
   const emits = defineEmits(['close', 'change']);
@@ -277,6 +279,13 @@
     if (code !== 0) {
       return;
     }
+    // 拼接结算信息(营销)
+    await OrderApi.getSettlementProduct(data.list.map((item) => item.id).join(',')).then((res) => {
+      if (res.code !== 0) {
+        return;
+      }
+      appendSettlementProduct(data.list, res.data);
+    });
     state.pagination.list = _.concat(state.pagination.list, data.list);
     state.pagination.total = data.total;
     state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';

+ 525 - 0
pages/goods/point.vue

@@ -0,0 +1,525 @@
+<!-- 秒杀商品详情 -->
+<template>
+  <s-layout :onShareAppMessage="shareInfo" navbar="goods">
+    <!-- 标题栏 -->
+    <detailNavbar />
+    <!-- 骨架屏 -->
+    <detailSkeleton v-if="state.skeletonLoading" />
+    <!-- 下架/售罄提醒 -->
+    <s-empty
+      v-else-if="state.goodsInfo === null || state.goodsInfo.activity_type !== PromotionActivityTypeEnum.POINT.type"
+      text="活动不存在或已结束"
+      icon="/static/soldout-empty.png"
+      showAction
+      actionText="再逛逛"
+      actionUrl="/pages/goods/list"
+    />
+    <block v-else>
+      <view class="detail-swiper-selector">
+        <!-- 商品图轮播 -->
+        <su-swiper
+          class="ss-m-b-14"
+          isPreview
+          :list="state.goodsSwiper"
+          dotStyle="tag"
+          imageMode="widthFix"
+          dotCur="bg-mask-40"
+          :seizeHeight="750"
+        />
+
+        <!-- 价格+标题 -->
+        <view class="title-card ss-m-y-14 ss-m-x-20 ss-p-x-20 ss-p-y-34">
+          <view class="price-box ss-flex ss-row-between ss-m-b-18">
+            <view class="ss-flex">
+              <view class="price-text ss-m-r-16">
+                {{ getShowPriceText }}
+              </view>
+              <view class="tig ss-flex ss-col-center">
+                <view class="tig-icon ss-flex ss-col-center ss-row-center">
+                  <text class="cicon-alarm"></text>
+                </view>
+                <view class="tig-title">积分价</view>
+              </view>
+            </view>
+          </view>
+          <view class="ss-flex ss-row-between ss-m-b-60">
+            <view class="origin-price ss-flex ss-col-center" v-if="state.goodsInfo.marketPrice">
+              原价
+              <view class="origin-price-text">
+                {{ fen2yuan(state.selectedSku.marketPrice || state.goodsInfo.marketPrice) }}
+              </view>
+            </view>
+          </view>
+
+          <view class="title-text ss-line-2 ss-m-b-6">{{ state.goodsInfo.name || '' }}</view>
+          <view class="subtitle-text ss-line-1">{{ state.goodsInfo.introduction }}</view>
+        </view>
+
+        <!-- 功能卡片 -->
+        <view class="detail-cell-card detail-card ss-flex-col">
+          <detail-cell-sku :sku="state.selectedSku" @tap="state.showSelectSku = true" />
+        </view>
+        <!-- 规格与数量弹框 -->
+        <s-select-seckill-sku
+          v-model="state.goodsInfo"
+          :show="state.showSelectSku"
+          :single-limit-count="activity.singleLimitCount"
+          @buy="onBuy"
+          @change="onSkuChange"
+          @close="state.showSelectSku = false"
+        />
+      </view>
+
+      <!-- 评价 -->
+      <detail-comment-card class="detail-comment-selector" :goodsId="state.goodsInfo.id" />
+      <!-- 详情 -->
+      <detail-content-card class="detail-content-selector" :content="state.goodsInfo.description" />
+
+      <!-- 详情tabbar -->
+      <detail-tabbar v-model="state.goodsInfo">
+        <view class="buy-box ss-flex ss-col-center ss-p-r-20">
+          <button
+            class="ss-reset-button origin-price-btn ss-flex-col"
+            v-if="state.goodsInfo.marketPrice"
+            @tap="sheep.$router.go('/pages/goods/index', { id: state.goodsInfo.id })"
+          >
+            <view>
+              <view class="btn-price">{{ fen2yuan(state.goodsInfo.marketPrice) }}</view>
+              <view>原价购买</view>
+            </view>
+          </button>
+          <button
+            class="ss-reset-button btn-box ss-flex-col"
+            @tap="state.showSelectSku = true"
+            :class="
+             state.goodsInfo.stock != 0
+                ? 'check-btn-box'
+                : 'disabled-btn-box'
+            "
+            :disabled="state.goodsInfo.stock === 0"
+          >
+            <view class="price-text">
+              {{getShowPriceText}}
+            </view>
+            <view v-if="state.goodsInfo.stock === 0">已售罄</view>
+            <view v-else>立即兑换</view>
+          </button>
+        </view>
+      </detail-tabbar>
+    </block>
+  </s-layout>
+</template>
+
+<script setup>
+  import { computed, reactive, ref, unref } from 'vue';
+  import { onLoad, onPageScroll } from '@dcloudio/uni-app';
+  import sheep from '@/sheep';
+  import { isEmpty } from 'lodash-es';
+  import { fen2yuan, formatGoodsSwiper } from '@/sheep/hooks/useGoods';
+  import detailNavbar from './components/detail/detail-navbar.vue';
+  import detailCellSku from './components/detail/detail-cell-sku.vue';
+  import detailTabbar from './components/detail/detail-tabbar.vue';
+  import detailSkeleton from './components/detail/detail-skeleton.vue';
+  import detailCommentCard from './components/detail/detail-comment-card.vue';
+  import detailContentCard from './components/detail/detail-content-card.vue';
+  import SpuApi from '@/sheep/api/product/spu';
+  import { PromotionActivityTypeEnum } from '@/sheep/util/const';
+  import PointApi from '@/sheep/api/promotion/point';
+
+  const headerBg = sheep.$url.css('/static/img/shop/goods/seckill-bg.png');
+  const btnBg = sheep.$url.css('/static/img/shop/goods/seckill-btn.png');
+  const disabledBtnBg = sheep.$url.css('/static/img/shop/goods/activity-btn-disabled.png');
+  const seckillBg = sheep.$url.css('/static/img/shop/goods/seckill-tip-bg.png');
+  const grouponBg = sheep.$url.css('/static/img/shop/goods/groupon-tip-bg.png');
+
+  onPageScroll(() => {
+  });
+  const state = reactive({
+    skeletonLoading: true,
+    goodsInfo: {},
+    showSelectSku: false,
+    goodsSwiper: [],
+    selectedSku: {},
+    showModel: false,
+    total: 0,
+    price: '',
+  });
+
+  // 规格变更
+  function onSkuChange(e) {
+    state.selectedSku = e;
+  }
+
+  // 立即购买
+  function onBuy(sku) {
+    sheep.$router.go('/pages/order/confirm', {
+      data: JSON.stringify({
+        order_type: 'goods',
+        buy_type: 'point',
+        pointActivityId: activity.value.id,
+        items: [
+          {
+            skuId: sku.id,
+            count: sku.count,
+          },
+        ],
+      }),
+    });
+  }
+
+  // 分享信息
+  // TODO puhui999: 下次 fix
+  const shareInfo = computed(() => {
+    if (isEmpty(unref(activity))) return {};
+    return sheep.$platform.share.getShareInfo(
+      {
+        title: activity.value.name,
+        image: sheep.$url.cdn(state.goodsInfo.picUrl),
+        params: {
+          page: '4',
+          query: activity.value.id,
+        },
+      },
+      {
+        type: 'goods', // 商品海报
+        title: activity.value.name, // 商品标题
+        image: sheep.$url.cdn(state.goodsInfo.picUrl), // 商品主图
+        price: state.goodsInfo.price, // 商品价格
+        marketPrice: state.goodsInfo.marketPrice, // 商品原价
+      },
+    );
+  });
+
+  const activity = ref();
+
+  const getShowPriceText = computed(() => {
+    let priceText = `${activity.value.point}积分${!activity.value.price ? '' : `+¥${fen2yuan(activity.value.price)}`}`;
+    if (!isEmpty(state.selectedSku)) {
+      const sku = state.selectedSku;
+      priceText = `${sku.point}积分${!sku.pointPrice ? '' : `+¥${fen2yuan(sku.pointPrice)}`}`;
+    }
+    return priceText;
+  });
+
+  // 查询活动
+  const getActivity = async (id) => {
+    const { data } = await PointApi.getPointActivity(id);
+    activity.value = data;
+    // 查询商品
+    await getSpu(data.spuId);
+  };
+
+  // 查询商品
+  const getSpu = async (id) => {
+    const { data } = await SpuApi.getSpuDetail(id);
+    data.activity_type = PromotionActivityTypeEnum.POINT.type;
+    state.goodsInfo = data;
+    state.goodsInfo.stock = Math.min(data.stock, activity.value.stock);
+    // 处理轮播图
+    state.goodsSwiper = formatGoodsSwiper(state.goodsInfo.sliderPicUrls);
+
+    // 价格、库存使用活动的
+    data.skus.forEach((sku) => {
+      const product = activity.value.products.find((product) => product.skuId === sku.id);
+      if (product) {
+        sku.point = product.point;
+        sku.pointPrice = product.price;
+        sku.stock = Math.min(sku.stock, product.stock);
+        // 设置限购数量
+        sku.limitCount = product.count;
+      } else {
+        // 找不到可能是没配置
+        sku.stock = 0;
+      }
+    });
+
+    state.skeletonLoading = false;
+  };
+
+  onLoad((options) => {
+    // 非法参数
+    if (!options.id) {
+      state.goodsInfo = null;
+      return;
+    }
+
+    // 查询活动
+    getActivity(options.id);
+  });
+</script>
+
+<style lang="scss" scoped>
+  .disabled-btn-box[disabled] {
+    background-color: transparent;
+  }
+
+  .detail-card {
+    background-color: $white;
+    margin: 14rpx 20rpx;
+    border-radius: 10rpx;
+    overflow: hidden;
+  }
+
+  // 价格标题卡片
+  .title-card {
+    width: 710rpx;
+    box-sizing: border-box;
+    // height: 320rpx;
+    background-size: 100% 100%;
+    border-radius: 10rpx;
+    background-image: v-bind(headerBg);
+    background-repeat: no-repeat;
+
+    .price-box {
+      .price-text {
+        font-size: 30rpx;
+        font-weight: 500;
+        color: #fff;
+        line-height: normal;
+        font-family: OPPOSANS;
+      }
+    }
+
+    .origin-price {
+      font-size: 24rpx;
+      font-weight: 400;
+      color: #fff;
+      opacity: 0.7;
+
+      .origin-price-text {
+        text-decoration: line-through;
+
+        font-family: OPPOSANS;
+
+        &::before {
+          content: '¥';
+        }
+      }
+    }
+
+    .tig {
+      border: 2rpx solid #ffffff;
+      border-radius: 4rpx;
+      width: 126rpx;
+      height: 38rpx;
+
+      .tig-icon {
+        width: 40rpx;
+        height: 40rpx;
+        margin-left: -2rpx;
+        background: #ffffff;
+        border-radius: 4rpx 0 0 4rpx;
+
+        .cicon-alarm {
+          font-size: 32rpx;
+          color: #fc6e6f;
+        }
+      }
+
+      .tig-title {
+        width: 86rpx;
+        font-size: 24rpx;
+        font-weight: 500;
+        line-height: normal;
+        color: #ffffff;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+      }
+    }
+
+    .countdown-title {
+      font-size: 26rpx;
+      font-weight: 500;
+      color: #ffffff;
+    }
+
+    .countdown-time {
+      font-size: 26rpx;
+      font-weight: 500;
+      color: #ffffff;
+
+      .countdown-h {
+        font-size: 24rpx;
+        font-family: OPPOSANS;
+        font-weight: 500;
+        color: #ffffff;
+        padding: 0 4rpx;
+        height: 40rpx;
+        background: rgba(#000000, 0.1);
+        border-radius: 6rpx;
+      }
+
+      .countdown-num {
+        font-size: 24rpx;
+        font-family: OPPOSANS;
+        font-weight: 500;
+        color: #ffffff;
+        width: 40rpx;
+        height: 40rpx;
+        background: rgba(#000000, 0.1);
+        border-radius: 6rpx;
+      }
+    }
+
+    .discounts-box {
+      .discounts-tag {
+        padding: 4rpx 10rpx;
+        font-size: 24rpx;
+        font-weight: 500;
+        border-radius: 4rpx;
+        color: var(--ui-BG-Main);
+        // background: rgba(#2aae67, 0.05);
+        background: var(--ui-BG-Main-tag);
+      }
+
+      .discounts-title {
+        font-size: 24rpx;
+        font-weight: 500;
+        color: var(--ui-BG-Main);
+        line-height: normal;
+      }
+
+      .cicon-forward {
+        color: var(--ui-BG-Main);
+        font-size: 24rpx;
+        line-height: normal;
+        margin-top: 4rpx;
+      }
+    }
+
+    .title-text {
+      font-size: 30rpx;
+      font-weight: bold;
+      line-height: 42rpx;
+      color: #fff;
+    }
+
+    .subtitle-text {
+      font-size: 26rpx;
+      font-weight: 400;
+      color: #ffffff;
+      line-height: 42rpx;
+      opacity: 0.9;
+    }
+  }
+
+  // 购买
+  .buy-box {
+    .check-btn-box {
+      width: 248rpx;
+      height: 80rpx;
+      font-size: 24rpx;
+      font-weight: 600;
+      margin-left: -36rpx;
+      background-image: v-bind(btnBg);
+      background-repeat: no-repeat;
+      background-size: 100% 100%;
+      color: #ffffff;
+      line-height: normal;
+      border-radius: 0px 40rpx 40rpx 0px;
+    }
+
+    .disabled-btn-box {
+      width: 248rpx;
+      height: 80rpx;
+      font-size: 24rpx;
+      font-weight: 600;
+      margin-left: -36rpx;
+      background-image: v-bind(disabledBtnBg);
+      background-repeat: no-repeat;
+      background-size: 100% 100%;
+      color: #999999;
+      line-height: normal;
+      border-radius: 0px 40rpx 40rpx 0px;
+    }
+
+    .btn-price {
+      font-family: OPPOSANS;
+
+      &::before {
+        content: '¥';
+      }
+    }
+
+    .origin-price-btn {
+      width: 236rpx;
+      height: 80rpx;
+      background: rgba(#ff5651, 0.1);
+      color: #ff6000;
+      border-radius: 40rpx 0px 0px 40rpx;
+      line-height: normal;
+      font-size: 24rpx;
+      font-weight: 500;
+
+      .no-original {
+        font-size: 28rpx;
+      }
+
+      .btn-title {
+        font-size: 28rpx;
+      }
+    }
+  }
+
+  //秒杀卡片
+  .seckill-box {
+    background: v-bind(seckillBg) no-repeat;
+    background-size: 100% 100%;
+  }
+
+  .groupon-box {
+    background: v-bind(grouponBg) no-repeat;
+    background-size: 100% 100%;
+  }
+
+  //活动卡片
+  .activity-box {
+    width: 100%;
+    height: 80rpx;
+    box-sizing: border-box;
+    margin-bottom: 10rpx;
+
+    .activity-title {
+      font-size: 26rpx;
+      font-weight: 500;
+      color: #ffffff;
+      line-height: 42rpx;
+
+      .activity-icon {
+        width: 38rpx;
+        height: 38rpx;
+      }
+    }
+
+    .activity-go {
+      width: 70rpx;
+      height: 32rpx;
+      background: #ffffff;
+      border-radius: 16rpx;
+      font-weight: 500;
+      color: #ff6000;
+      font-size: 24rpx;
+      line-height: normal;
+    }
+  }
+
+  .model-box {
+    .title {
+      font-size: 36rpx;
+      font-weight: bold;
+      color: #333333;
+    }
+
+    .subtitle {
+      font-size: 26rpx;
+      font-weight: 500;
+      color: #333333;
+    }
+  }
+
+  image {
+    width: 100%;
+    height: 100%;
+  }
+</style>

+ 7 - 2
pages/goods/seckill.vue

@@ -225,8 +225,8 @@
   const getActivity = async (id) => {
     const { data } = await SeckillApi.getSeckillActivity(id);
     activity.value = data;
-    timeStatusEnum.value = getTimeStatusEnum(activity.startTime, activity.endTime);
-
+    timeStatusEnum.value = getTimeStatusEnum(activity.value.startTime, activity.value.endTime);
+    state.percent = 100 - (data.stock / data.totalStock) * 100;
     // 查询商品
     await getSpu(data.spuId);
   };
@@ -284,6 +284,7 @@
   .disabled-btn-box[disabled] {
     background-color: transparent;
   }
+
   .detail-card {
     background-color: $white;
     margin: 14rpx 20rpx;
@@ -374,6 +375,7 @@
       font-size: 26rpx;
       font-weight: 500;
       color: #ffffff;
+
       .countdown-h {
         font-size: 24rpx;
         font-family: OPPOSANS;
@@ -384,6 +386,7 @@
         background: rgba(#000000, 0.1);
         border-radius: 6rpx;
       }
+
       .countdown-num {
         font-size: 24rpx;
         font-family: OPPOSANS;
@@ -467,6 +470,7 @@
       line-height: normal;
       border-radius: 0px 40rpx 40rpx 0px;
     }
+
     .btn-price {
       font-family: OPPOSANS;
 
@@ -484,6 +488,7 @@
       line-height: normal;
       font-size: 24rpx;
       font-weight: 500;
+
       .no-original {
         font-size: 28rpx;
       }

+ 1 - 1
pages/order/aftersale/apply.vue

@@ -208,7 +208,7 @@
     state.itemId = parseInt(options.itemId);
 
     // 读取订单信息
-    const { code, data } = await OrderApi.getOrder(state.orderId);
+    const { code, data } = await OrderApi.getOrderDetail(state.orderId);
     if (code !== 0) {
       return;
     }

+ 3 - 2
pages/order/confirm.vue

@@ -143,8 +143,7 @@
           v-if="state.orderInfo.price.discountPrice > 0"
         >
           <view class="item-title">活动优惠</view>
-          <view class="ss-flex ss-col-center">
-            <!--                @tap="state.showDiscount = true" TODO puhui999:【折扣】后续要把优惠信息打进去 -->
+          <view class="ss-flex ss-col-center" @tap="state.showDiscount = true">
             <text class="item-value text-red">
               -¥{{ fen2yuan(state.orderInfo.price.discountPrice) }}
             </text>
@@ -295,6 +294,7 @@
       combinationActivityId: state.orderPayload.combinationActivityId,
       combinationHeadId: state.orderPayload.combinationHeadId,
       seckillActivityId: state.orderPayload.seckillActivityId,
+      pointActivityId: state.orderPayload.pointActivityId,
     });
     if (code !== 0) {
       return;
@@ -325,6 +325,7 @@
       combinationActivityId: state.orderPayload.combinationActivityId,
       combinationHeadId: state.orderPayload.combinationHeadId,
       seckillActivityId: state.orderPayload.seckillActivityId,
+      pointActivityId: state.orderPayload.pointActivityId,
     });
     if (code !== 0) {
       return;

+ 9 - 5
pages/order/detail.vue

@@ -127,7 +127,11 @@
     </view>
 
     <!--  自提核销  -->
-    <PickUpVerify :order-info="state.orderInfo" :systemStore="systemStore" ref="pickUpVerifyRef"></PickUpVerify>
+    <PickUpVerify
+      :order-info="state.orderInfo"
+      :systemStore="systemStore"
+      ref="pickUpVerifyRef"
+    ></PickUpVerify>
 
     <!-- 订单信息 -->
     <view class="notice-box">
@@ -305,7 +309,7 @@
     uni.showModal({
       title: '提示',
       content: '确定要取消订单吗?',
-      success: async function(res) {
+      success: async function (res) {
         if (!res.confirm) {
           return;
         }
@@ -394,11 +398,11 @@
     let res;
     if (state.comeinType === 'wechat') {
       // TODO 芋艿:微信场景下
-      res = await OrderApi.getOrder(id, {
+      res = await OrderApi.getOrderDetail(id, {
         merchant_trade_no: state.merchantTradeNo,
       });
     } else {
-      res = await OrderApi.getOrder(id);
+      res = await OrderApi.getOrderDetail(id);
     }
     if (res.code === 0) {
       state.orderInfo = res.data;
@@ -451,7 +455,7 @@
     color: rgba(#fff, 0.9);
     width: 100%;
     background: v-bind(headerBg) no-repeat,
-    linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
+      linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
     background-size: 750rpx 100%;
     box-sizing: border-box;
 

+ 8 - 8
pages/order/express/log.vue

@@ -13,10 +13,10 @@
         </uni-swiper-dot>
         <view class="log-card-msg">
           <!-- TODO 芋艿:【物流】优化点:展示状态 -->
-<!--          <view class="ss-flex ss-m-b-8">-->
-<!--            <view>物流状态:</view>-->
-<!--            <view class="warning-color">{{ state.info.status_text }}</view>-->
-<!--          </view>-->
+          <!--          <view class="ss-flex ss-m-b-8">-->
+          <!--            <view>物流状态:</view>-->
+          <!--            <view class="warning-color">{{ state.info.status_text }}</view>-->
+          <!--          </view>-->
           <view class="ss-m-b-8">快递单号:{{ state.info.logisticsNo }}</view>
           <view>快递公司:{{ state.info.logisticsName }}</view>
         </view>
@@ -35,9 +35,9 @@
           </view>
           <view class="log-content-msg">
             <!-- TODO 芋艿:【物流】优化点:展示状态 -->
-<!--            <view class="log-msg-title ss-m-b-20">-->
-<!--              {{ item.status_text }}-->
-<!--            </view>-->
+            <!--            <view class="log-msg-title ss-m-b-20">-->
+            <!--              {{ item.status_text }}-->
+            <!--            </view>-->
             <view class="log-msg-desc ss-m-b-16">{{ item.content }}</view>
             <view class="log-msg-date ss-m-b-40">
               {{ sheep.$helper.timeFormat(item.time, 'yyyy-mm-dd hh:MM:ss') }}
@@ -78,7 +78,7 @@
   }
 
   async function getOrderDetail(id) {
-    const { data } = await OrderApi.getOrder(id)
+    const { data } = await OrderApi.getOrderDetail(id);
     state.info = data;
   }
 

+ 9 - 10
pages/order/pickUpVerify.vue

@@ -19,15 +19,15 @@
       <view class="num">{{ orderInfo.pickUpVerifyCode }}</view>
       <view class="rules">
         <!-- TODO puhui999: 需要后端放回:使用 receiveTime 即可 -->
-<!--        <view class="item">-->
-<!--          <view class="rulesTitle flex flex-wrap align-center">-->
-<!--            核销时间-->
-<!--          </view>-->
-<!--          <view class="info">-->
-<!--            每日:-->
-<!--            <text class="time">2020-2-+52</text>-->
-<!--          </view>-->
-<!--        </view>-->
+        <view class="item">
+          <view class="rulesTitle flex flex-wrap align-center">
+            核销时间
+          </view>
+          <view class="info">
+            每日:
+            <text class="time">2020-2-+52</text>
+          </view>
+        </view>
         <view class="item">
           <view class="rulesTitle flex flex-wrap align-center">
             <text class="iconfont icon-shuoming1"></text>
@@ -138,7 +138,6 @@
 </script>
 
 <style scoped lang="scss">
-  // TODO puhui999: 样式需要调整有 bug
   .borRadius14 {
     border-radius: 14rpx !important;
   }

+ 26 - 15
pages/pay/index.vue

@@ -81,7 +81,7 @@
   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';
+  import { getPayMethods, goPayResult } from '@/sheep/platform/pay';
 
   const userWallet = computed(() => sheep.$store('user').userWallet);
 
@@ -135,12 +135,22 @@
 
   // 状态转换:payOrder.status => payStatus
   function checkPayStatus() {
-    if (state.orderInfo.status === 10
-      || state.orderInfo.status === 20 ) { // 支付成功
+    if (state.orderInfo.status === 10 || state.orderInfo.status === 20) {
+      // 支付成功
       state.payStatus = 2;
+      // 跳转回支付成功页
+      uni.showModal({
+        title: '提示',
+        content: '订单已支付',
+        showCancel: false,
+        success: function () {
+          goPayResult(state.orderInfo.id, state.orderType);
+        },
+      });
       return;
     }
-    if (state.orderInfo.status === 30) { // 支付关闭
+    if (state.orderInfo.status === 30) {
+      // 支付关闭
       state.payStatus = -1;
       return;
     }
@@ -155,26 +165,26 @@
   // 设置支付订单信息
   async function setOrder(id) {
     // 获得支付订单信息
-    const { data, code } = await PayOrderApi.getOrder(id);
+    const { data, code } = await PayOrderApi.getOrder(id, true);
     if (code !== 0 || !data) {
       state.payStatus = -2;
       return;
     }
     state.orderInfo = data;
-    // 获得支付方式
-    await setPayMethods();
     // 设置支付状态
     checkPayStatus();
+    // 获得支付方式
+    await setPayMethods();
   }
 
   // 获得支付方式
   async function setPayMethods() {
-    const { data, code } = await PayChannelApi.getEnableChannelCodeList(state.orderInfo.appId)
+    const { data, code } = await PayChannelApi.getEnableChannelCodeList(state.orderInfo.appId);
     if (code !== 0) {
-      return
+      return;
     }
-    state.payMethods = getPayMethods(data)
-    state.payMethods.find(item => {
+    state.payMethods = getPayMethods(data);
+    state.payMethods.find((item) => {
       if (item.value && !item.disabled) {
         state.payment = item.value;
         return true;
@@ -183,9 +193,11 @@
   }
 
   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;
     }
@@ -214,7 +226,6 @@
       position: relative;
       padding: 60rpx 20rpx 40rpx;
 
-
       .money-text {
         color: $red;
         font-size: 46rpx;

+ 4 - 1
pages/pay/result.vue

@@ -126,7 +126,10 @@
         // #endif
         // 特殊:获得商品订单信息
         if (state.orderType === 'goods') {
-          const { data, code } = await OrderApi.getOrder(state.orderInfo.merchantOrderId);
+          const { data, code } = await OrderApi.getOrderDetail(
+            state.orderInfo.merchantOrderId,
+            true,
+          );
           if (code === 0) {
             state.tradeOrder = data;
           }

+ 4 - 4
sheep/api/pay/order.js

@@ -2,11 +2,11 @@ import request from '@/sheep/request';
 
 const PayOrderApi = {
   // 获得支付订单
-  getOrder: (id) => {
+  getOrder: (id, sync) => {
     return request({
       url: '/pay/order/get',
       method: 'GET',
-      params: { id }
+      params: { id, sync },
     });
   },
   // 提交支付订单
@@ -14,9 +14,9 @@ const PayOrderApi = {
     return request({
       url: '/pay/order/submit',
       method: 'POST',
-      data
+      data,
     });
-  }
+  },
 };
 
 export default PayOrderApi;

+ 12 - 0
sheep/api/product/spu.js

@@ -13,6 +13,18 @@ const SpuApi = {
       },
     });
   },
+  // 获得商品结算信息
+  getSettlementProduct: (spuIds) => {
+    return request({
+      url: '/trade/order/settlement-product',
+      method: 'GET',
+      params: { spuIds },
+      custom: {
+        showLoading: false,
+        showError: false,
+      },
+    });
+  },
   // 获得商品 SPU 分页
   getSpuPage: (params) => {
     return request({

+ 30 - 0
sheep/api/promotion/point.js

@@ -0,0 +1,30 @@
+import request from '@/sheep/request';
+
+const PointApi = {
+  // 获得积分商城活动分页
+  getPointActivityPage: (params) => {
+    return request({ url: 'promotion/point-activity/page', method: 'GET', params });
+  },
+
+  // 获得积分商城活动列表,基于活动编号数组
+  getPointActivityListByIds: (ids) => {
+    return request({
+      url: '/promotion/point-activity/list-by-ids',
+      method: 'GET',
+      params: {
+        ids,
+      },
+    });
+  },
+
+  // 获得积分商城活动明细
+  getPointActivity: (id) => {
+    return request({
+      url: 'promotion/point-activity/get-detail',
+      method: 'GET',
+      params: { id },
+    });
+  },
+};
+
+export default PointApi;

+ 15 - 2
sheep/api/trade/order.js

@@ -53,6 +53,18 @@ const OrderApi = {
       },
     });
   },
+  // 获得商品结算信息
+  getSettlementProduct: (spuIds) => {
+    return request({
+      url: '/trade/order/settlement-product',
+      method: 'GET',
+      params: { spuIds },
+      custom: {
+        showLoading: false,
+        showError: false,
+      },
+    });
+  },
   // 创建订单
   createOrder: (data) => {
     return request({
@@ -61,13 +73,14 @@ const OrderApi = {
       data,
     });
   },
-  // 获得订单
-  getOrder: (id) => {
+  // 获得订单详细:sync 是可选参数
+  getOrderDetail: (id, sync) => {
     return request({
       url: `/trade/order/get-detail`,
       method: 'GET',
       params: {
         id,
+        sync,
       },
       custom: {
         showLoading: false,

+ 196 - 0
sheep/components/countDown/index.vue

@@ -0,0 +1,196 @@
+<!-- TODO 霖:是不是怎么复用 s-count-down 组件 -->
+<template>
+  <view class="time" :style="justifyLeft">
+    <text class="" v-if="tipText">{{ tipText }}</text>
+    <text
+      class="styleAll p6"
+      v-if="isDay === true"
+      :style="{ background: bgColor.bgColor, color: bgColor.Color }"
+      >{{ day }}{{ bgColor.isDay ? '天' : '' }}</text
+    >
+    <text
+      class="timeTxt"
+      v-if="dayText"
+      :style="{ width: bgColor.timeTxtwidth, color: bgColor.bgColor }"
+      >{{ dayText }}</text
+    >
+    <text
+      class="styleAll"
+      :class="isCol ? 'timeCol' : ''"
+      :style="{ background: bgColor.bgColor, color: bgColor.Color, width: bgColor.width }"
+      >{{ hour }}</text
+    >
+    <text
+      class="timeTxt"
+      v-if="hourText"
+      :class="isCol ? 'whit' : ''"
+      :style="{ width: bgColor.timeTxtwidth, color: bgColor.bgColor }"
+      >{{ hourText }}</text
+    >
+    <text
+      class="styleAll"
+      :class="isCol ? 'timeCol' : ''"
+      :style="{ background: bgColor.bgColor, color: bgColor.Color, width: bgColor.width }"
+      >{{ minute }}</text
+    >
+    <text
+      class="timeTxt"
+      v-if="minuteText"
+      :class="isCol ? 'whit' : ''"
+      :style="{ width: bgColor.timeTxtwidth, color: bgColor.bgColor }"
+      >{{ minuteText }}</text
+    >
+    <text
+      class="styleAll"
+      :class="isCol ? 'timeCol' : ''"
+      :style="{ background: bgColor.bgColor, color: bgColor.Color, width: bgColor.width }"
+      >{{ second }}</text
+    >
+    <text class="timeTxt" v-if="secondText">{{ secondText }}</text>
+  </view>
+</template>
+
+<script>
+  export default {
+    name: 'countDown',
+    props: {
+      justifyLeft: {
+        type: String,
+        default: '',
+      },
+      //距离开始提示文字
+      tipText: {
+        type: String,
+        default: '倒计时',
+      },
+      dayText: {
+        type: String,
+        default: '天',
+      },
+      hourText: {
+        type: String,
+        default: '时',
+      },
+      minuteText: {
+        type: String,
+        default: '分',
+      },
+      secondText: {
+        type: String,
+        default: '秒',
+      },
+      datatime: {
+        type: Number,
+        default: 0,
+      },
+      isDay: {
+        type: Boolean,
+        default: true,
+      },
+      isCol: {
+        type: Boolean,
+        default: false,
+      },
+      bgColor: {
+        type: Object,
+        default: null,
+      },
+    },
+    data: function () {
+      return {
+        day: '00',
+        hour: '00',
+        minute: '00',
+        second: '00',
+      };
+    },
+    created: function () {
+      this.show_time();
+    },
+    mounted: function () {},
+    methods: {
+      show_time: function () {
+        let that = this;
+
+        function runTime() {
+          //时间函数
+          let intDiff = that.datatime - Date.parse(new Date()) / 1000; //获取数据中的时间戳的时间差;
+          let day = 0,
+            hour = 0,
+            minute = 0,
+            second = 0;
+          if (intDiff > 0) {
+            //转换时间
+            if (that.isDay === true) {
+              day = Math.floor(intDiff / (60 * 60 * 24));
+            } else {
+              day = 0;
+            }
+            hour = Math.floor(intDiff / (60 * 60)) - day * 24;
+            minute = Math.floor(intDiff / 60) - day * 24 * 60 - hour * 60;
+            second = Math.floor(intDiff) - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60;
+            if (hour <= 9) hour = '0' + hour;
+            if (minute <= 9) minute = '0' + minute;
+            if (second <= 9) second = '0' + second;
+            that.day = day;
+            that.hour = hour;
+            that.minute = minute;
+            that.second = second;
+          } else {
+            that.day = '00';
+            that.hour = '00';
+            that.minute = '00';
+            that.second = '00';
+          }
+        }
+        runTime();
+        setInterval(runTime, 1000);
+      },
+    },
+  };
+</script>
+
+<style scoped>
+  .p6 {
+    padding: 0 8rpx;
+  }
+  .styleAll {
+    /* color: #fff; */
+    font-size: 24rpx;
+    height: 36rpx;
+    line-height: 36rpx;
+    border-radius: 6rpx;
+    text-align: center;
+    /* padding: 0 6rpx; */
+  }
+  .timeTxt {
+    text-align: center;
+    /* width: 16rpx; */
+    height: 36rpx;
+    line-height: 36rpx;
+    display: inline-block;
+  }
+  .whit {
+    color: #fff !important;
+  }
+  .time {
+    display: flex;
+    justify-content: center;
+  }
+
+  .red {
+    color: #fc4141;
+    margin: 0 4rpx;
+  }
+
+  .timeCol {
+    /* width: 40rpx;
+    height: 40rpx;
+    line-height: 40rpx;
+    text-align:center;
+    border-radius: 6px;
+    background: #fff;
+    font-size: 24rpx; */
+    color: #e93323;
+  }
+</style>

+ 187 - 37
sheep/components/s-activity-pop/s-activity-pop.vue

@@ -2,34 +2,81 @@
 <template>
   <su-popup :show="show" type="bottom" round="20" @close="emits('close')" showClose>
     <view class="model-box">
-      <view class="title ss-m-t-16 ss-m-l-20 ss-flex">营销活动</view>
+      <view class="title ss-m-t-16 ss-m-l-20 ss-flex">优惠</view>
+      <view v-if="state.rewardActivity && state.rewardActivity.id > 0">
+        <view class="titleLi">促销</view>
+        <scroll-view
+          class="model-content"
+          scroll-y
+          :scroll-with-animation="false"
+          :enable-back-to-top="true"
+        >
+          <view
+            class="actBox"
+            v-for="(item, index) in getRewardActivityRuleGroupDescriptions(state.rewardActivity)"
+            :key="index"
+          >
+            <view
+              class="boxCont ss-flex ss-col-top ss-m-b-40"
+              @tap="onGoodsList(state.rewardActivity)"
+            >
+              <view class="model-content-tag ss-flex ss-row-center">{{ item.name }}</view>
+              <view class="model-content-title">
+                <view class="contBu">
+                  {{ item.values.join(';') }}
+                </view>
+                <view class="ss-m-b-24 cotBu-txt">
+                  {{ sheep.$helper.timeFormat(state.rewardActivity.startTime, 'yyyy.mm.dd') }}
+                  -
+                  {{ sheep.$helper.timeFormat(state.rewardActivity.endTime, 'yyyy.mm.dd') }}
+                </view>
+              </view>
+              <text class="cicon-forward" />
+            </view>
+          </view>
+        </scroll-view>
+      </view>
+      <view class="titleLi">可领优惠券</view>
       <scroll-view
-        class="model-content ss-m-t-50"
+        class="model-content"
         scroll-y
         :scroll-with-animation="false"
         :enable-back-to-top="true"
+        v-if="state.couponInfo.length"
       >
-        <view v-for="item in state.activityInfo" :key="item.id">
-          <view class="ss-flex ss-col-top ss-m-b-40" @tap="onGoodsList(item)">
-            <view class="model-content-tag ss-flex ss-row-center">满减</view>
-            <view class="ss-m-l-20 model-content-title ss-flex-1">
-              <view class="ss-m-b-24" v-for="rule in state.activityMap[item.id]?.rules" :key="rule">
-                {{ formatRewardActivityRule(state.activityMap[item.id], rule) }}
+        <view class="actBox" v-for="item in state.couponInfo" :key="item.id">
+          <view class="boxCont ss-flex ss-col-top ss-m-b-40">
+            <view class="model-content-tag2">
+              <view class="usePrice"> ¥{{ fen2yuan(item.discountPrice) }} </view>
+              <view class="impose"> 满¥{{ fen2yuan(item.usePrice) }}可用 </view>
+            </view>
+            <view class="model-content-title2">
+              <view class="contBu">
+                {{ item.name }}
+              </view>
+              <view class="ss-m-b-24 cotBu-txt">
+                {{
+                  item.validityType == 1
+                    ? sheep.$helper.timeFormat(item.validStartTime, 'yyyy.mm.dd') -
+                      sheep.$helper.timeFormat(item.validEndTime, 'yyyy.mm.dd')
+                    : '领取后' + item.fixedStartTerm + '-' + item.fixedEndTerm + '天可用'
+                }}
               </view>
             </view>
-            <text class="cicon-forward" />
+            <view class="coupon" @click.stop="getBuy(item.id)" v-if="item.canTake"> 立即领取 </view>
+            <view class="coupon2" v-else> 已领取 </view>
           </view>
         </view>
       </scroll-view>
+      <view class="nullBox" v-else> 暂无可领优惠券 </view>
     </view>
   </su-popup>
 </template>
 <script setup>
   import sheep from '@/sheep';
-  import { computed, reactive, watch } from 'vue';
-  import RewardActivityApi from '@/sheep/api/promotion/rewardActivity';
-  import { formatRewardActivityRule } from '@/sheep/hooks/useGoods';
-
+  import { getRewardActivityRuleGroupDescriptions } from '@/sheep/hooks/useGoods';
+  import { computed, reactive, watch, ref } from 'vue';
+  import { fen2yuan } from '@/sheep/hooks/useGoods';
   const props = defineProps({
     modelValue: {
       type: Object,
@@ -42,26 +89,14 @@
   });
   const emits = defineEmits(['close']);
   const state = reactive({
-    activityInfo: computed(() => props.modelValue),
-    activityMap: {}
+    rewardActivity: computed(() => props.modelValue.rewardActivity),
+    couponInfo: computed(() => props.modelValue.couponInfo),
   });
 
-  watch(
-    () => props.show,
-    () => {
-      // 展示的情况下,加载每个活动的详细信息
-      if (props.show) {
-        state.activityInfo?.forEach(activity => {
-          RewardActivityApi.getRewardActivity(activity.id).then(res => {
-            if (res.code !== 0) {
-              return;
-            }
-            state.activityMap[activity.id] = res.data;
-          })
-        });
-      }
-    },
-  );
+  // 领取优惠劵
+  const getBuy = (id) => {
+    emits('get', id);
+  };
 
   function onGoodsList(e) {
     sheep.$router.go('/pages/activity/index', {
@@ -72,34 +107,149 @@
 <style lang="scss" scoped>
   .model-box {
     height: 60vh;
+
     .title {
+      justify-content: center;
       font-size: 36rpx;
       height: 80rpx;
       font-weight: bold;
       color: #333333;
     }
   }
+
   .model-content {
+    height: fit-content;
+    max-height: 380rpx;
     padding: 0 20rpx;
     box-sizing: border-box;
+    margin-top: 20rpx;
+
     .model-content-tag {
-      background: rgba(#ff6911, 0.1);
-      font-size: 24rpx;
+      // background: rgba(#ff6911, 0.1);
+      font-size: 35rpx;
       font-weight: 500;
       color: #ff6911;
-      line-height: 42rpx;
-      width: 68rpx;
-      height: 32rpx;
-      border-radius: 5rpx;
+      line-height: 150rpx;
+      width: 200rpx;
+      height: 150rpx;
+      text-align: center;
+
+      // border-radius: 5rpx;
     }
+
     .model-content-title {
+      width: 450rpx;
+      height: 150rpx;
       font-size: 26rpx;
       font-weight: 500;
       color: #333333;
+      overflow: hidden;
     }
+
     .cicon-forward {
       font-size: 28rpx;
       color: #999999;
+      margin: 0 auto;
     }
   }
+
+  // 新增的
+  .titleLi {
+    margin: 10rpx 0 10rpx 20rpx;
+    font-size: 26rpx;
+  }
+
+  .actBox {
+    width: 700rpx;
+    height: 150rpx;
+    background-color: #fff2f2;
+    margin: 10rpx auto;
+    border-radius: 10rpx;
+  }
+
+  .boxCont {
+    width: 700rpx;
+    height: 150rpx;
+    align-items: center;
+  }
+
+  .contBu {
+    height: 80rpx;
+    line-height: 80rpx;
+    overflow: hidden;
+    font-size: 30rpx;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    -o-text-overflow: ellipsis;
+  }
+
+  .cotBu-txt {
+    height: 70rpx;
+    line-height: 70rpx;
+    font-size: 25rpx;
+    color: #999999;
+  }
+
+  .model-content-tag2 {
+    font-size: 35rpx;
+    font-weight: 500;
+    color: #ff6911;
+    width: 200rpx;
+    height: 150rpx;
+    text-align: center;
+  }
+
+  .usePrice {
+    width: 200rpx;
+    height: 90rpx;
+    line-height: 100rpx;
+    // background-color: red;
+  }
+
+  .impose {
+    width: 200rpx;
+    height: 50rpx;
+    // line-height: 75rpx;
+    font-size: 23rpx;
+    // background-color: gold;
+  }
+
+  .model-content-title2 {
+    width: 330rpx;
+    height: 150rpx;
+    font-size: 26rpx;
+    font-weight: 500;
+    color: #333333;
+    overflow: hidden;
+  }
+
+  .coupon {
+    width: 150rpx;
+    height: 50rpx;
+    line-height: 50rpx;
+    background-color: rgb(255, 68, 68);
+    color: white;
+    border-radius: 30rpx;
+    text-align: center;
+    font-size: 25rpx;
+  }
+
+  .coupon2 {
+    width: 150rpx;
+    height: 50rpx;
+    line-height: 50rpx;
+    background-color: rgb(203, 192, 191);
+    color: white;
+    border-radius: 30rpx;
+    text-align: center;
+    font-size: 25rpx;
+  }
+  .nullBox {
+    width: 100%;
+    height: 300rpx;
+    font-size: 25rpx;
+    line-height: 300rpx;
+    text-align: center;
+    color: #999999;
+  }
 </style>

+ 2 - 0
sheep/components/s-block-item/s-block-item.vue

@@ -39,6 +39,8 @@
     <s-groupon-block v-if="type === 'PromotionCombination'" :data="data" :styles="styles" />
     <!-- 营销组件:秒杀 -->
     <s-seckill-block v-if="type === 'PromotionSeckill'" :data="data" :styles="styles" />
+    <!-- 营销组件:积分商城 -->
+    <s-point-block v-if="type === 'PromotionPoint'" :data="data" :styles="styles" />
     <!-- 营销组件:小程序直播(暂时没有这个功能) -->
     <s-live-block v-if="type === 'MpLive'" :data="data" :styles="styles" />
     <!-- 营销组件:优惠券 -->

+ 10 - 28
sheep/components/s-discount-list/s-discount-list.vue

@@ -15,25 +15,11 @@
         :scroll-with-animation="false"
         :enable-back-to-top="true"
       >
-        <view v-for="(item, index) in state.orderInfo.promo_infos" :key="index">
-          <view class="ss-flex ss-m-b-40 subtitle">
-            <view>共{{ item.goods_ids.length }}件,</view>
-            <view v-if="item.activity_type === 'full_discount'">
-              满{{ item.discount_rule.full }}打{{ item.discount_rule.discount }}折,已减
-            </view>
-            <view v-if="item.activity_type === 'full_gift'">满赠</view>
-            <view v-if="item.activity_type === 'full_reduce'">
-              满{{ item.discount_rule.full }}减{{ item.discount_rule.discount }},已减
-            </view>
-            <view class="price-text">¥{{ item.promo_discount_money || '0.00' }}</view>
+        <view v-for="(item, index) in state.orderInfo.promotions" :key="index">
+          <!-- 不展示积分、优惠劵、会员折扣,因为它们已经单独展示了 -->
+          <view class="ss-flex ss-m-b-40 subtitle" v-if="[1, 2, 3, 4, 5, 6].includes(item.type)">
+            <view> {{ item.description }} </view>
           </view>
-          <scroll-view class="scroll-box" scroll-x scroll-anchoring>
-            <view class="ss-flex">
-              <view v-for="i in item.goods_ids" :key="i">
-                <image class="content-img" :src="sheep.$url.cdn(getGoodsImg(i))" />
-              </view>
-            </view>
-          </scroll-view>
         </view>
       </scroll-view>
     </view>
@@ -44,7 +30,6 @@
 </template>
 <script setup>
   import { computed, reactive } from 'vue';
-  import sheep from '@/sheep';
   const props = defineProps({
     promoInfo: {
       type: Array,
@@ -67,28 +52,22 @@
   const state = reactive({
     orderInfo: computed(() => props.modelValue),
   });
-  const getGoodsImg = (e) => {
-    let goodsImg = '';
-    state.orderInfo.goods_list.forEach((i) => {
-      if (e == i.goods_id) {
-        goodsImg = i.goods.image;
-      }
-    });
-    return goodsImg;
-  };
 </script>
 <style lang="scss" scoped>
   .model-box {
     height: 60vh;
   }
+
   .model-content {
     height: 54vh;
   }
+
   .modal-footer {
     width: 100%;
     height: 120rpx;
     background: #fff;
   }
+
   .confirm-btn {
     width: 710rpx;
     margin-left: 20rpx;
@@ -97,17 +76,20 @@
     border-radius: 40rpx;
     color: #fff;
   }
+
   .content-img {
     width: 140rpx;
     height: 140rpx;
     margin-right: 20rpx;
     margin-bottom: 20rpx;
   }
+
   .subtitle {
     font-size: 28rpx;
     font-weight: 500;
     color: #333333;
   }
+
   .price-text {
     color: #ff3000;
   }

+ 11 - 0
sheep/components/s-goods-card/s-goods-card.vue

@@ -144,6 +144,8 @@
   import { computed, reactive, onMounted } from 'vue';
   import sheep from '@/sheep';
   import SpuApi from '@/sheep/api/product/spu';
+  import OrderApi from '@/sheep/api/trade/order';
+  import { appendSettlementProduct } from '@/sheep/hooks/useGoods';
 
   // 布局类型
   const LayoutTypeEnum = {
@@ -238,6 +240,15 @@
   onMounted(async () => {
     // 加载商品列表
     state.goodsList = await getGoodsListByIds(spuIds.join(','));
+    // 拼接结算信息(营销)
+    await OrderApi.getSettlementProduct(state.goodsList.map((item) => item.id).join(',')).then(
+      (res) => {
+        if (res.code !== 0) {
+          return;
+        }
+        appendSettlementProduct(state.goodsList, res.data);
+      },
+    );
     // 只有双列布局时需要
     if (layoutType === LayoutTypeEnum.TWO_COL) {
       // 分列

+ 204 - 48
sheep/components/s-goods-column/s-goods-column.vue

@@ -11,11 +11,7 @@
       <view v-if="tagStyle.show" class="tag-icon-box">
         <image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image>
       </view>
-      <image
-        class="xs-img-box"
-        :src="sheep.$url.cdn(data.image || data.picUrl)"
-        mode="aspectFit"
-      ></image>
+      <image class="xs-img-box" :src="sheep.$url.cdn(data.image || data.picUrl)" mode="aspectFit" />
       <view
         v-if="goodsFields.title?.show || goodsFields.name?.show || goodsFields.price?.show"
         class="xs-goods-content ss-flex-col ss-row-around"
@@ -27,13 +23,34 @@
         >
           {{ data.title || data.name }}
         </view>
+        <!-- 活动信息 -->
+        <view class="iconBox" v-if="data.promotionType > 0 || data.rewardActivity">
+          <view class="card" v-if="discountText">{{ discountText }}</view>
+          <view
+            class="card2"
+            v-for="item in getRewardActivityRuleItemDescriptions(data.rewardActivity).slice(0, 1)"
+            :key="item"
+          >
+            {{ item }}
+          </view>
+        </view>
         <view
           v-if="goodsFields.price?.show"
           class="xs-goods-price font-OPPOSANS"
           :style="[{ color: goodsFields.price.color }]"
         >
-          <text class="price-unit ss-font-24">{{ priceUnit }}</text>
-          {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
+          <!-- 活动价格 -->
+          <text v-if="data.activityType && data.activityType === PromotionActivityTypeEnum.POINT.type">
+            {{ data.point }}积分
+            {{ !data.pointPrice || data.pointPrice === 0 ? '' : `+${fen2yuan(data.pointPrice)}元` }}
+          </text>
+          <template v-else>
+            <text class="price-unit ss-font-24">{{ priceUnit }}</text>
+            <text v-if="data.promotionPrice > 0">{{ fen2yuan(data.promotionPrice) }}</text>
+            <text v-else>
+              {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
+            </text>
+          </template>
         </view>
       </view>
     </view>
@@ -60,13 +77,34 @@
         >
           {{ data.title || data.name }}
         </view>
+        <!-- 活动信息 -->
+        <view class="iconBox" v-if="data.promotionType > 0 || data.rewardActivity">
+          <view class="card" v-if="discountText">{{ discountText }}</view>
+          <view
+            class="card2"
+            v-for="item in getRewardActivityRuleItemDescriptions(data.rewardActivity).slice(0, 1)"
+            :key="item"
+          >
+            {{ item }}
+          </view>
+        </view>
         <view
           v-if="goodsFields.price?.show"
           class="sm-goods-price font-OPPOSANS"
           :style="[{ color: goodsFields.price.color }]"
         >
-          <text class="price-unit ss-font-24">{{ priceUnit }}</text>
-          {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
+          <!-- 活动价格 -->
+          <text v-if="data.activityType && data.activityType === PromotionActivityTypeEnum.POINT.type">
+            {{ data.point }}积分
+            {{ !data.pointPrice || data.pointPrice === 0 ? '' : `+${fen2yuan(data.pointPrice)}元` }}
+          </text>
+          <template v-else>
+            <text class="price-unit ss-font-24">{{ priceUnit }}</text>
+            <text v-if="data.promotionPrice > 0">{{ fen2yuan(data.promotionPrice) }}</text>
+            <text v-else>
+              {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
+            </text>
+          </template>
         </view>
       </view>
     </view>
@@ -74,13 +112,9 @@
     <!-- md卡片:竖向,一行放两个,图上内容下 -->
     <view v-if="size === 'md'" class="md-goods-card ss-flex-col" :style="[elStyles]" @tap="onClick">
       <view v-if="tagStyle.show" class="tag-icon-box">
-        <image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image>
+        <image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)" />
       </view>
-      <image
-        class="md-img-box"
-        :src="sheep.$url.cdn(data.image || data.picUrl)"
-        mode="widthFix"
-      ></image>
+      <image class="md-img-box" :src="sheep.$url.cdn(data.image || data.picUrl)" mode="widthFix" />
       <view
         class="md-goods-content ss-flex-col ss-row-around ss-p-b-20 ss-p-t-20 ss-p-x-16"
         :id="elId"
@@ -110,16 +144,36 @@
             </view>
           </view>
         </slot>
+        <!-- 活动信息 -->
+        <view class="iconBox" v-if="data.promotionType > 0 || data.rewardActivity">
+          <view class="card" v-if="discountText">{{ discountText }}</view>
+          <view
+            class="card2"
+            v-for="item in getRewardActivityRuleItemDescriptions(data.rewardActivity).slice(0, 1)"
+            :key="item"
+          >
+            {{ item }}
+          </view>
+        </view>
         <view class="ss-flex ss-col-bottom">
           <view
             v-if="goodsFields.price?.show"
             class="md-goods-price ss-m-t-16 font-OPPOSANS ss-m-r-10"
             :style="[{ color: goodsFields.price.color }]"
           >
-            <text class="price-unit ss-font-24">{{ priceUnit }}</text>
-            {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
+            <!-- 活动价格 -->
+            <text v-if="data.activityType && data.activityType === PromotionActivityTypeEnum.POINT.type">
+              {{ data.point }}积分
+              {{ !data.pointPrice || data.pointPrice === 0 ? '' : `+${fen2yuan(data.pointPrice)}元` }}
+            </text>
+            <template v-else>
+              <text class="price-unit ss-font-24">{{ priceUnit }}</text>
+              <text v-if="data.promotionPrice > 0">{{ fen2yuan(data.promotionPrice) }}</text>
+              <text v-else>
+                {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
+              </text>
+            </template>
           </view>
-
           <view
             v-if="
               (goodsFields.original_price?.show || goodsFields.marketPrice?.show) &&
@@ -163,7 +217,7 @@
         class="lg-img-box"
         :src="sheep.$url.cdn(data.image || data.picUrl)"
         mode="aspectFill"
-      ></image>
+      />
       <view class="lg-goods-content ss-flex-1 ss-flex-col ss-row-between ss-p-b-10 ss-p-t-20">
         <view>
           <view
@@ -189,21 +243,38 @@
               </view>
             </view>
           </slot>
-          <view class="ss-flex ss-col-bottom ss-m-t-10">
+          <!-- 活动信息 -->
+          <view class="iconBox" v-if="data.promotionType > 0 || data.rewardActivity">
+            <view class="card" v-if="discountText">{{ discountText }}</view>
             <view
-              v-if="goodsFields.price?.show"
-              class="lg-goods-price ss-m-r-12 ss-flex ss-col-bottom font-OPPOSANS"
-              :style="[{ color: goodsFields.price.color }]"
+              class="card2"
+              v-for="item in getRewardActivityRuleItemDescriptions(data.rewardActivity).slice(0, 1)"
+              :key="item"
             >
-              <text class="ss-font-24">{{ priceUnit }}</text>
-              {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
+              {{ item }}
+            </view>
+          </view>
+          <view v-if="goodsFields.price?.show" class="ss-flex ss-col-bottom font-OPPOSANS">
+            <view class="sl-goods-price ss-m-r-12" :style="[{ color: goodsFields.price.color }]">
+              <!-- 活动价格 -->
+              <text v-if="data.activityType && data.activityType === PromotionActivityTypeEnum.POINT.type">
+                {{ data.point }}积分
+                {{ !data.pointPrice || data.pointPrice === 0 ? '' : `+${fen2yuan(data.pointPrice)}元` }}
+              </text>
+              <template v-else>
+                <text class="price-unit ss-font-24">{{ priceUnit }}</text>
+                <text v-if="data.promotionPrice > 0">{{ fen2yuan(data.promotionPrice) }}</text>
+                <text v-else>
+                  {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
+                </text>
+              </template>
             </view>
             <view
               v-if="
                 (goodsFields.original_price?.show || goodsFields.marketPrice?.show) &&
                 (data.original_price > 0 || data.marketPrice > 0)
               "
-              class="goods-origin-price ss-flex ss-col-bottom font-OPPOSANS"
+              class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex"
               :style="[{ color: originPriceColor }]"
             >
               <text class="price-unit ss-font-20">{{ priceUnit }}</text>
@@ -217,22 +288,20 @@
       </view>
 
       <slot name="cart">
-        <view class="buy-box ss-flex ss-col-center ss-row-center" v-if="buttonShow"> 去购买 </view>
+        <view class="buy-box ss-flex ss-col-center ss-row-center" v-if="buttonShow"> 去购买</view>
       </slot>
     </view>
 
     <!-- sl卡片:竖向型,一行放一个,图片上内容下边 -->
     <view v-if="size === 'sl'" class="sl-goods-card ss-flex-col" :style="[elStyles]" @tap="onClick">
       <view v-if="tagStyle.show" class="tag-icon-box">
-        <image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image>
+        <image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)" />
       </view>
-
       <image
         class="sl-img-box"
         :src="sheep.$url.cdn(data.image || data.picUrl)"
         mode="aspectFill"
-      ></image>
-
+      />
       <view class="sl-goods-content">
         <view>
           <view
@@ -262,10 +331,31 @@
               </view>
             </view>
           </slot>
+          <!-- 活动信息 -->
+          <view class="iconBox" v-if="data.promotionType > 0 || data.rewardActivity">
+            <view class="card" v-if="discountText">{{ discountText }}</view>
+            <view
+              class="card2"
+              v-for="item in getRewardActivityRuleItemDescriptions(data.rewardActivity).slice(0, 1)"
+              :key="item"
+            >
+              {{ item }}
+            </view>
+          </view>
           <view v-if="goodsFields.price?.show" class="ss-flex ss-col-bottom font-OPPOSANS">
             <view class="sl-goods-price ss-m-r-12" :style="[{ color: goodsFields.price.color }]">
-              <text class="price-unit ss-font-24">{{ priceUnit }}</text>
-              {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
+              <!-- 活动价格 -->
+              <text v-if="data.activityType && data.activityType === PromotionActivityTypeEnum.POINT.type">
+                {{ data.point }}积分
+                {{ !data.pointPrice || data.pointPrice === 0 ? '' : `+${fen2yuan(data.pointPrice)}元` }}
+              </text>
+              <template v-else>
+                <text class="price-unit ss-font-24">{{ priceUnit }}</text>
+                <text v-if="data.promotionPrice > 0">{{ fen2yuan(data.promotionPrice) }}</text>
+                <text v-else>
+                  {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
+                </text>
+              </template>
             </view>
             <view
               v-if="
@@ -321,14 +411,17 @@
    * @event {Function()} click                    - 点击卡片
    *
    */
-  import { computed, reactive, getCurrentInstance, onMounted, nextTick } from 'vue';
+  import { computed, getCurrentInstance, nextTick, onMounted } from 'vue';
   import sheep from '@/sheep';
-  import { fen2yuan, formatSales } from '@/sheep/hooks/useGoods';
-  import { formatStock } from '@/sheep/hooks/useGoods';
+  import {
+    fen2yuan,
+    formatExchange,
+    formatSales,
+    formatStock,
+    getRewardActivityRuleItemDescriptions,
+  } from '@/sheep/hooks/useGoods';
   import { isArray } from 'lodash-es';
-
-  // 数据
-  const state = reactive({});
+  import { PromotionActivityTypeEnum } from '@/sheep/util/const';
 
   // 接收参数
   const props = defineProps({
@@ -337,17 +430,29 @@
       default() {
         return {
           // 商品价格
-          price: { show: true },
+          price: {
+            show: true,
+          },
           // 库存
-          stock: { show: true },
+          stock: {
+            show: true,
+          },
           // 商品名称
-          name: { show: true },
+          name: {
+            show: true,
+          },
           // 商品介绍
-          introduction: { show: true },
+          introduction: {
+            show: true,
+          },
           // 市场价
-          marketPrice: { show: true },
+          marketPrice: {
+            show: true,
+          },
           // 销量
-          salesCount: { show: true },
+          salesCount: {
+            show: true,
+          },
         };
       },
     },
@@ -417,6 +522,17 @@
     },
   });
 
+  // 优惠文案
+  const discountText = computed(() => {
+    const promotionType = props.data.promotionType;
+    if (promotionType === 4) {
+      return '限时优惠';
+    } else if (promotionType === 6) {
+      return '会员价';
+    }
+    return undefined;
+  });
+
   // 组件样式
   const elStyles = computed(() => {
     return {
@@ -432,10 +548,18 @@
   const salesAndStock = computed(() => {
     let text = [];
     if (props.goodsFields.salesCount?.show) {
-      text.push(formatSales(props.data.sales_show_type, props.data.salesCount));
+      if (props.data.activityType && props.data.activityType === PromotionActivityTypeEnum.POINT.type) {
+        text.push(formatExchange(props.data.sales_show_type, (props.data.pointTotalStock || 0) - (props.data.pointStock || 0)));
+      }else {
+        text.push(formatSales(props.data.sales_show_type, props.data.salesCount));
+      }
     }
     if (props.goodsFields.stock?.show) {
-      text.push(formatStock(props.data.stock_show_type, props.data.stock));
+      if (props.data.activityType && props.data.activityType === PromotionActivityTypeEnum.POINT.type) {
+        text.push(formatStock(props.data.stock_show_type, props.data.pointTotalStock));
+      }else {
+        text.push(formatStock(props.data.stock_show_type, props.data.stock));
+      }
     }
     return text.join(' | ');
   });
@@ -454,7 +578,10 @@
   function getGoodsPriceCardWH() {
     if (props.size === 'md') {
       const view = uni.createSelectorQuery().in(proxy);
-      view.select(`#${elId}`).fields({ size: true, scrollOffset: true });
+      view.select(`#${elId}`).fields({
+        size: true,
+        scrollOffset: true,
+      });
       view.exec((data) => {
         let totalHeight = 0;
         const goodsPriceCard = data[0];
@@ -763,4 +890,33 @@
       color: #ffffff;
     }
   }
+
+  .card {
+    width: fit-content;
+    height: fit-content;
+    padding: 2rpx 10rpx;
+    background-color: red;
+    color: #ffffff;
+    font-size: 24rpx;
+    margin-top: 5rpx;
+  }
+
+  .card2 {
+    width: fit-content;
+    height: fit-content;
+    padding: 2rpx 10rpx;
+    background-color: rgb(255, 242, 241);
+    color: #ff2621;
+    font-size: 24rpx;
+    margin: 5rpx 0 5rpx 5rpx;
+  }
+
+  .iconBox {
+    width: 100%;
+    height: fit-content;
+    margin-top: 10rpx;
+    display: flex;
+    justify-content: flex-start;
+    flex-wrap: wrap;
+  }
 </style>

+ 10 - 2
sheep/components/s-goods-item/s-goods-item.vue

@@ -28,6 +28,14 @@
             >
               ¥{{ fen2yuan(price) }}
             </view>
+            <view v-if="point && Number(price) > 0">+</view>
+            <view class="price-text ss-flex ss-col-center" v-if="point">
+              <image
+                :src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
+                class="point-img"
+              ></image>
+              <view>{{ point }}</view>
+            </view>
             <view v-if="num" class="total-text ss-flex ss-col-center">x {{ num }}</view>
             <slot name="priceSuffix"></slot>
           </view>
@@ -88,7 +96,7 @@
       type: [String, Number],
       default: 0,
     },
-    score: {
+    point: {
       type: [String, Number],
       default: '',
     },
@@ -113,7 +121,7 @@
 </script>
 
 <style lang="scss" scoped>
-  .score-img {
+  .point-img {
     width: 36rpx;
     height: 36rpx;
     margin: 0 4rpx;

+ 328 - 0
sheep/components/s-point-block/s-point-block.vue

@@ -0,0 +1,328 @@
+<!-- 装修商品组件:【积分商城】商品卡片 -->
+<template>
+  <!-- 商品卡片 -->
+  <view>
+    <!-- 布局1. 单列大图(上图,下内容)-->
+    <view
+      v-if="layoutType === LayoutTypeEnum.ONE_COL_BIG_IMG && state.spuList.length"
+      class="goods-sl-box"
+    >
+      <view
+        class="goods-box"
+        v-for="item in state.spuList"
+        :key="item.id"
+        :style="[{ marginBottom: data.space * 2 + 'rpx' }]"
+      >
+        <s-goods-column
+          class=""
+          size="sl"
+          :goodsFields="data.fields"
+          :tagStyle="data.badge"
+          :data="item"
+          :titleColor="data.fields.name?.color"
+          :subTitleColor="data.fields.introduction.color"
+          :topRadius="data.borderRadiusTop"
+          :bottomRadius="data.borderRadiusBottom"
+          @click="sheep.$router.go('/pages/goods/point', { id: item.activityId })"
+        >
+          <!-- 购买按钮 -->
+          <template v-slot:cart>
+            <button class="ss-reset-button cart-btn" :style="[buyStyle]">
+              {{ btnBuy.type === 'text' ? btnBuy.text : '' }}
+            </button>
+          </template>
+        </s-goods-column>
+      </view>
+    </view>
+
+    <!-- 布局2. 单列小图(左图,右内容) -->
+    <view
+      v-if="layoutType === LayoutTypeEnum.ONE_COL_SMALL_IMG && state.spuList.length"
+      class="goods-lg-box"
+    >
+      <view
+        class="goods-box"
+        :style="[{ marginBottom: data.space + 'px' }]"
+        v-for="item in state.spuList"
+        :key="item.id"
+      >
+        <s-goods-column
+          class="goods-card"
+          size="lg"
+          :goodsFields="data.fields"
+          :data="item"
+          :tagStyle="data.badge"
+          :titleColor="data.fields.name?.color"
+          :subTitleColor="data.fields.introduction.color"
+          :topRadius="data.borderRadiusTop"
+          :bottomRadius="data.borderRadiusBottom"
+          @tap="sheep.$router.go('/pages/goods/point', { id: item.activityId })"
+        >
+          <!-- 购买按钮 -->
+          <template v-slot:cart>
+            <button class="ss-reset-button cart-btn" :style="[buyStyle]">
+              {{ btnBuy.type === 'text' ? btnBuy.text : '' }}
+            </button>
+          </template>
+        </s-goods-column>
+      </view>
+    </view>
+
+    <!-- 布局3. 双列(每一列:上图,下内容)-->
+    <view
+      v-if="layoutType === LayoutTypeEnum.TWO_COL && state.spuList.length"
+      class="goods-md-wrap ss-flex ss-flex-wrap ss-col-top"
+    >
+      <view class="goods-list-box">
+        <view
+          class="left-list"
+          :style="[{ paddingRight: data.space + 'rpx', marginBottom: data.space + 'px' }]"
+          v-for="item in state.leftSpuList"
+          :key="item.id"
+        >
+          <s-goods-column
+            class="goods-md-box"
+            size="md"
+            :goodsFields="data.fields"
+            :tagStyle="data.badge"
+            :data="item"
+            :titleColor="data.fields.name?.color"
+            :subTitleColor="data.fields.introduction.color"
+            :topRadius="data.borderRadiusTop"
+            :bottomRadius="data.borderRadiusBottom"
+            :titleWidth="330 - marginLeft - marginRight"
+            @click="sheep.$router.go('/pages/goods/seckill', { id: item.activityId })"
+            @getHeight="calculateGoodsColumn($event, 'left')"
+          >
+            <!-- 购买按钮 -->
+            <template v-slot:cart>
+              <button class="ss-reset-button cart-btn" :style="[buyStyle]">
+                {{ btnBuy.type === 'text' ? btnBuy.text : '' }}
+              </button>
+            </template>
+          </s-goods-column>
+        </view>
+      </view>
+      <view class="goods-list-box">
+        <view
+          class="right-list"
+          :style="[{ paddingLeft: data.space + 'rpx', marginBottom: data.space + 'px' }]"
+          v-for="item in state.rightSpuList"
+          :key="item.id"
+        >
+          <s-goods-column
+            class="goods-md-box"
+            size="md"
+            :goodsFields="data.fields"
+            :tagStyle="data.badge"
+            :data="item"
+            :titleColor="data.fields.name?.color"
+            :subTitleColor="data.fields.introduction.color"
+            :topRadius="data.borderRadiusTop"
+            :bottomRadius="data.borderRadiusBottom"
+            :titleWidth="330 - marginLeft - marginRight"
+            @click="sheep.$router.go('/pages/goods/seckill', { id: item.activityId })"
+            @getHeight="calculateGoodsColumn($event, 'right')"
+          >
+            <!-- 购买按钮 -->
+            <template v-slot:cart>
+              <button class="ss-reset-button cart-btn" :style="[buyStyle]">
+                {{ btnBuy.type === 'text' ? btnBuy.text : '' }}
+              </button>
+            </template>
+          </s-goods-column>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+  /**
+   * 商品卡片
+   */
+  import { computed, onMounted, reactive, ref } from 'vue';
+  import sheep from '@/sheep';
+  import SpuApi from '@/sheep/api/product/spu';
+  import PointApi from '@/sheep/api/promotion/point';
+  import { PromotionActivityTypeEnum } from '@/sheep/util/const';
+
+  // 布局类型
+  const LayoutTypeEnum = {
+    // 单列大图
+    ONE_COL_BIG_IMG: 'oneColBigImg',
+    // 双列
+    TWO_COL: 'twoCol',
+    // 单列小图
+    ONE_COL_SMALL_IMG: 'oneColSmallImg',
+  };
+
+  const state = reactive({
+    spuList: [],
+    leftSpuList: [],
+    rightSpuList: [],
+  });
+  const props = defineProps({
+    data: {
+      type: Object,
+      default() {},
+    },
+    styles: {
+      type: Object,
+      default() {},
+    },
+  });
+
+  const { layoutType, btnBuy, activityIds } = props.data || {};
+  const { marginLeft, marginRight } = props.styles || {};
+
+  // 购买按钮样式
+  const buyStyle = computed(() => {
+    if (btnBuy.type === 'text') {
+      // 文字按钮:线性渐变背景颜色
+      return {
+        background: `linear-gradient(to right, ${btnBuy.bgBeginColor}, ${btnBuy.bgEndColor})`,
+      };
+    }
+    if (btnBuy.type === 'img') {
+      // 图片按钮
+      return {
+        width: '54rpx',
+        height: '54rpx',
+        background: `url(${sheep.$url.cdn(btnBuy.imgUrl)}) no-repeat`,
+        backgroundSize: '100% 100%',
+      };
+    }
+  });
+
+  //region 商品瀑布流布局
+  // 下一个要处理的商品索引
+  let count = 0;
+  // 左列的高度
+  let leftHeight = 0;
+  // 右列的高度
+  let rightHeight = 0;
+
+  /**
+   * 计算商品在左列还是右列
+   * @param height 商品的高度
+   * @param where 添加到哪一列
+   */
+  function calculateGoodsColumn(height = 0, where = 'left') {
+    // 处理完
+    if (!state.spuList[count]) return;
+    // 增加列的高度
+    if (where === 'left') leftHeight += height;
+    if (where === 'right') rightHeight += height;
+    // 添加到矮的一列
+    if (leftHeight <= rightHeight) {
+      state.leftSpuList.push(state.spuList[count]);
+    } else {
+      state.rightSpuList.push(state.spuList[count]);
+    }
+    // 计数
+    count++;
+  }
+
+  //endregion
+
+  /**
+   * 根据商品编号列表,获取商品列表
+   * @param ids 商品编号列表
+   * @return {Promise<undefined>} 商品列表
+   */
+  async function getPointActivityDetailList(ids) {
+    const { data } = await PointApi.getPointActivityListByIds(ids);
+    return data;
+  }
+
+  /**
+   * 根据商品编号,获取商品详情
+   * @param ids 商品编号列表
+   * @return {Promise<undefined>} 商品列表
+   */
+  async function getSpuDetail(ids) {
+    const { data: spu } = await SpuApi.getSpuDetail(ids);
+    return spu;
+  }
+
+  // 初始化
+  onMounted(async () => {
+    // 加载活动列表
+    const activityList = await getPointActivityDetailList(activityIds.join(','));
+    // 循环获取活动商品SPU详情并添加到spuList
+    for (const activity of activityList) {
+      state.spuList.push(await getSpuDetail(activity.spuId));
+    }
+
+    // 循环活动列表
+    activityList.forEach((activity) => {
+      // 查找对应的 spu 并更新价格
+      const spu = state.spuList.find((spu) => activity.spuId === spu.id);
+      if (spu) {
+        spu.pointStock = activity.stock
+        spu.pointTotalStock = activity.totalStock
+        spu.point = activity.point
+        spu.pointPrice = activity.price
+        // 赋值活动ID,为了点击跳转详情页
+        spu.activityId = activity.id;
+        // 赋值活动类型
+        spu.activityType = PromotionActivityTypeEnum.POINT.type;
+      }
+    });
+
+    // 只有双列布局时需要
+    if (layoutType === LayoutTypeEnum.TWO_COL) {
+      // 分列
+      calculateGoodsColumn();
+    }
+  });
+</script>
+
+<style lang="scss" scoped>
+  .goods-md-wrap {
+    width: 100%;
+  }
+
+  .goods-list-box {
+    width: 50%;
+    box-sizing: border-box;
+
+    .left-list {
+      &:nth-last-child(1) {
+        margin-bottom: 0 !important;
+      }
+    }
+
+    .right-list {
+      &:nth-last-child(1) {
+        margin-bottom: 0 !important;
+      }
+    }
+  }
+
+  .goods-box {
+    &:nth-last-of-type(1) {
+      margin-bottom: 0 !important;
+    }
+  }
+
+  .goods-md-box,
+  .goods-sl-box,
+  .goods-lg-box {
+    position: relative;
+
+    .cart-btn {
+      position: absolute;
+      bottom: 18rpx;
+      right: 20rpx;
+      z-index: 11;
+      height: 50rpx;
+      line-height: 50rpx;
+      padding: 0 20rpx;
+      border-radius: 25rpx;
+      font-size: 24rpx;
+      color: #fff;
+    }
+  }
+</style>

+ 458 - 0
sheep/components/s-point-card/s-point-card.vue

@@ -0,0 +1,458 @@
+<template>
+  <view>
+    <!-- md卡片:竖向,一行放两个,图上内容下 -->
+    <view v-if="size === 'md'" class="md-goods-card ss-flex-col" :style="[elStyles]" @tap="onClick">
+      <image
+        class="md-img-box"
+        :src="sheep.$url.cdn(data.image)"
+        mode="widthFix"
+        @load="calculatePanelHeight"
+      ></image>
+      <view
+        class="md-goods-content ss-flex-col ss-row-around ss-p-b-20 ss-p-t-20 ss-p-x-16"
+        :id="elId"
+      >
+        <view
+          v-if="goodsFields.title?.show"
+          class="md-goods-title ss-line-1"
+          :style="[{ color: titleColor, width: titleWidth ? titleWidth + 'rpx' : '' }]"
+        >
+          {{ data.title }}
+        </view>
+        <view
+          v-if="goodsFields.subtitle?.show"
+          class="md-goods-subtitle ss-m-t-16 ss-line-1"
+          :style="[{ color: subTitleColor }]"
+        >
+          {{ data.subtitle }}
+        </view>
+        <view class="ss-col-bottom">
+          <view
+            v-if="goodsFields.score_price?.show"
+            class="md-goods-price ss-m-t-16 font-OPPOSANS ss-m-r-10 ss-flex"
+            :style="[{ color: goodsFields.score_price.color }]"
+          >
+            <view>{{ Number(data.price[0]) > 0 ? '¥' + data.price[0] + '+' : '' }}</view>
+            <image
+              :src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
+              class="score-img"
+            ></image>
+            {{ data.score }}
+          </view>
+
+          <view
+            v-if="goodsFields.price?.show && data.original_price > 0"
+            class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex"
+            :style="[{ color: goodsFields.price.color }]"
+          >
+            <text class="price-unit ss-font-20">{{ priceUnit }}</text>
+            <view class="ss-m-l-8">{{ data.original_price }}</view>
+          </view>
+        </view>
+
+        <view class="ss-m-t-16 ss-flex ss-col-center ss-flex-wrap">
+          <view class="sales-text">{{ salesAndStock }}</view>
+        </view>
+      </view>
+
+      <slot name="cart">
+        <view class="cart-box ss-flex ss-col-center ss-row-center">
+          <image class="cart-icon" src="/static/img/shop/tabbar/category2.png" mode=""></image>
+        </view>
+      </slot>
+    </view>
+    <!-- lg卡片:横向型,一行放一个,图片左内容右边  -->
+    <view
+      v-if="size === 'lg'"
+      class="lg-goods-card ss-flex ss-col-stretch"
+      :style="[elStyles]"
+      @tap="onClick"
+    >
+      <image class="lg-img-box" :src="sheep.$url.cdn(data.image)" mode="aspectFill"></image>
+      <view class="lg-goods-content ss-flex-1 ss-flex-col ss-row-between ss-p-b-10 ss-p-t-20">
+        <view class="ss-m-r-20">
+          <view
+            v-if="goodsFields.title?.show"
+            class="lg-goods-title ss-line-2"
+            :style="[{ color: titleColor }]"
+          >
+            {{ data.title }}
+          </view>
+          <view
+            v-if="goodsFields.subtitle?.show"
+            class="lg-goods-subtitle ss-m-t-10 ss-line-1"
+            :style="[{ color: subTitleColor }]"
+          >
+            {{ data.subtitle }}
+          </view>
+        </view>
+        <view>
+          <view class="ss-m-t-10">
+            <view
+              v-if="goodsFields.score_price?.show"
+              class="lg-goods-price ss-m-r-12 ss-flex ss-col-bottom font-OPPOSANS"
+              :style="[{ color: goodsFields.score_price.color }]"
+            >
+              <view>{{ Number(data.price[0]) > 0 ? '¥' + data.price[0] + '+' : '' }}</view>
+              <image
+                :src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
+                class="score-img"
+              ></image>
+              {{ data.score }}
+            </view>
+            <view
+              v-if="goodsFields.price?.show && data.original_price > 0"
+              class="goods-origin-price ss-flex ss-col-bottom font-OPPOSANS"
+              :style="[{ color: goodsFields.price.color }]"
+            >
+              <text class="price-unit ss-font-20">{{ priceUnit }}</text>
+              <view class="ss-m-l-8">{{ data.original_price }}</view>
+            </view>
+          </view>
+          <view class="ss-m-t-16 ss-flex ss-col-center ss-flex-wrap">
+            <view class="sales-text">{{ salesAndStock }}</view>
+          </view>
+        </view>
+      </view>
+
+      <slot name="cart"
+      ><view class="buy-box ss-flex ss-col-center ss-row-center">去兑换</view></slot
+      >
+    </view>
+    <!-- sl卡片:竖向型,一行放一个,图片上内容下边 -->
+    <view v-if="size === 'sl'" class="sl-goods-card ss-flex-col" @tap="onClick">
+      <image class="sl-img-box" :src="sheep.$url.cdn(data.image)" mode="aspectFill"></image>
+
+      <view class="sl-goods-content ss-flex-col ss-row-between ss-p-b-20 ss-p-t-20">
+        <view class="ss-m-b-20">
+          <view class="sl-goods-title ss-line-1 ss-p-l-16 ss-p-r-16">
+            {{ data.title }}
+          </view>
+          <view v-if="data.subtitle" class="sl-goods-subtitle ss-p-l-16 ss-p-r-16 ss-m-t-16">
+            {{ data.subtitle }}
+          </view>
+        </view>
+        <view>
+          <slot name="activity">
+            <view
+              v-if="data.promos?.length"
+              class="tag-box ss-flex ss-col-center ss-flex-wrap ss-p-l-16 ss-p-r-16"
+            >
+              <view
+                class="activity-tag ss-m-r-10 ss-m-t-16"
+                v-for="item in data.promos"
+                :key="item.id"
+              >
+                {{ item.title }}
+              </view>
+            </view>
+          </slot>
+          <view class="ss-flex ss-col-bottom ss-p-l-16 ss-p-r-16 font-OPPOSANS">
+            <view class="sl-goods-price ss-m-r-12 ss-flex">
+              <view>{{ Number(data.price[0]) > 0 ? '¥' + data.price[0] + '+' : '' }}</view>
+              <image
+                :src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
+                class="score-img"
+              ></image>
+              <view>{{ data.score ? data.score : '' }}</view>
+            </view>
+            <view
+              v-if="data.original_price > 0"
+              class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex"
+            >
+              <text class="price-unit ss-font-20">¥</text>
+              <view class="ss-m-l-8">{{ data.original_price }}</view>
+            </view>
+          </view>
+          <view class="ss-p-l-16 ss-p-r-16 ss-m-t-16 ss-flex ss-flex-wrap">
+            <view class="sales-text">{{ salesAndStock }}</view>
+          </view>
+        </view>
+      </view>
+
+      <slot name="cart"
+      ><view class="buy-box ss-flex ss-col-center ss-row-center">去兑换</view></slot
+      >
+    </view>
+  </view>
+</template>
+<script setup>
+  import { computed, getCurrentInstance } from 'vue';
+  import sheep from '@/sheep';
+  import { formatSales } from '@/sheep/hooks/useGoods';
+  import { formatStock } from '@/sheep/hooks/useGoods';
+  /**
+   * 订单卡片
+   *
+   * @property {String} img 											- 图片
+   * @property {String} title 										- 标题
+   * @property {Number} titleWidth = 0								- 标题宽度,默认0,单位rpx
+   * @property {String} skuText 										- 规格
+   * @property {String | Number} score 								- 积分
+   * @property {String | Number} price 								- 价格
+   * @property {String | Number} originalPrice 						- 单购价
+   * @property {String} priceColor 									- 价格颜色
+   * @property {Number | String} num									- 数量
+   *
+   */
+  const props = defineProps({
+    goodsFields: {
+      type: [Array, Object],
+      default() {
+        return {
+          title: { show: true },
+          subtitle: { show: true },
+          price: { show: true },
+          original_price: { show: true },
+          sales: { show: true },
+          stock: { show: true },
+        };
+      },
+    },
+    tagStyle: {
+      type: Object,
+      default: {},
+    },
+    data: {
+      type: Object,
+      default: {},
+    },
+    size: {
+      type: String,
+      default: 'sl',
+    },
+    background: {
+      type: String,
+      default: '',
+    },
+    topRadius: {
+      type: Number,
+      default: 0,
+    },
+    bottomRadius: {
+      type: Number,
+      default: 0,
+    },
+    titleWidth: {
+      type: Number,
+      default: 0,
+    },
+    titleColor: {
+      type: String,
+      default: '#333',
+    },
+    priceUnit: {
+      type: String,
+      default: '¥',
+    },
+    subTitleColor: {
+      type: String,
+      default: '#999999',
+    },
+  });
+  // 组件样式
+  const elStyles = computed(() => {
+    return {
+      background: props.background,
+      'border-top-left-radius': props.topRadius + 'px',
+      'border-top-right-radius': props.topRadius + 'px',
+      'border-bottom-left-radius': props.bottomRadius + 'px',
+      'border-bottom-right-radius': props.bottomRadius + 'px',
+    };
+  });
+  const emits = defineEmits(['click', 'getHeight']);
+  const onClick = () => {
+    emits('click');
+  };
+  // 格式化销量、库存信息
+  const salesAndStock = computed(() => {
+    let text = [];
+    text.push(formatSales(props.data.sales_show_type, props.data.sales));
+    text.push(formatStock(props.data.stock_show_type, props.data.stock));
+    return text.join(' | ');
+  });
+  // 获取实时卡片高度
+  const { proxy } = getCurrentInstance();
+  const elId = `sheep_${Math.ceil(Math.random() * 10e5).toString(36)}`;
+  function calculatePanelHeight(e) {
+    if (props.size === 'md') {
+      const view = uni.createSelectorQuery().in(proxy);
+      view.select(`#${elId}`).fields({ size: true, scrollOffset: true });
+      view.exec((data) => {
+        const goodsPriceCard = data[0];
+        const card = {
+          width: goodsPriceCard.width,
+          height: (goodsPriceCard.width / e.detail.width) * e.detail.height + goodsPriceCard.height,
+        };
+        emits('getHeight', card.height);
+      });
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .price-unit {
+    margin-right: -4px;
+  }
+  .sales-text {
+    display: table;
+    font-size: 24rpx;
+    transform: scale(0.8);
+    margin-left: -16rpx;
+    color: #c4c4c4;
+  }
+
+  // md
+  .md-goods-card {
+    overflow: hidden;
+    width: 100%;
+    position: relative;
+    z-index: 1;
+    background-color: $white;
+    position: relative;
+
+    .md-img-box {
+      width: 100%;
+    }
+
+    .md-goods-title {
+      font-size: 26rpx;
+      color: #333;
+      width: 100%;
+    }
+    .md-goods-subtitle {
+      font-size: 24rpx;
+      font-weight: 400;
+      color: #999999;
+    }
+
+    .md-goods-price {
+      font-size: 30rpx;
+      color: $red;
+      line-height: 36rpx;
+    }
+
+    .cart-box {
+      width: 54rpx;
+      height: 54rpx;
+      background: linear-gradient(90deg, #fe8900, #ff5e00);
+      border-radius: 50%;
+      position: absolute;
+      bottom: 50rpx;
+      right: 20rpx;
+      z-index: 2;
+
+      .cart-icon {
+        width: 30rpx;
+        height: 30rpx;
+      }
+    }
+  }
+
+  // lg
+  .lg-goods-card {
+    overflow: hidden;
+    position: relative;
+    z-index: 1;
+    background-color: $white;
+    height: 280rpx;
+
+    .lg-img-box {
+      width: 280rpx;
+      height: 280rpx;
+      margin-right: 20rpx;
+    }
+
+    .lg-goods-title {
+      font-size: 28rpx;
+      font-weight: 500;
+      color: #333333;
+      // line-height: 36rpx;
+      // width: 410rpx;
+    }
+    .lg-goods-subtitle {
+      font-size: 24rpx;
+      font-weight: 400;
+      color: #999999;
+      line-height: 30rpx;
+      // width: 410rpx;
+    }
+
+    .lg-goods-price {
+      font-size: 30rpx;
+      color: $red;
+      line-height: 36rpx;
+    }
+
+    .buy-box {
+      position: absolute;
+      bottom: 20rpx;
+      right: 20rpx;
+      z-index: 2;
+      width: 120rpx;
+      height: 50rpx;
+      background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
+      border-radius: 25rpx;
+      font-size: 24rpx;
+      color: #ffffff;
+    }
+    .tag-box {
+      width: 100%;
+    }
+  }
+  .sl-goods-card {
+    overflow: hidden;
+    position: relative;
+    z-index: 1;
+    width: 100%;
+    background-color: $white;
+
+    .sl-img-box {
+      width: 100%;
+      height: 360rpx;
+    }
+
+    .sl-goods-title {
+      font-size: 26rpx;
+      color: #333;
+      width: 100%;
+      box-sizing: border-box;
+    }
+    .sl-goods-subtitle {
+      font-size: 24rpx;
+      font-weight: 400;
+      color: #999999;
+      line-height: 30rpx;
+      width: 100%;
+      box-sizing: border-box;
+    }
+
+    .sl-goods-price {
+      font-size: 30rpx;
+      color: $red;
+    }
+
+    .buy-box {
+      position: absolute;
+      bottom: 20rpx;
+      right: 20rpx;
+      z-index: 2;
+      width: 148rpx;
+      height: 50rpx;
+      background: linear-gradient(90deg, #fe8900, #ff5e00);
+      border-radius: 25rpx;
+      font-size: 24rpx;
+      color: #ffffff;
+    }
+  }
+  .goods-origin-price {
+    font-size: 20rpx;
+    color: #c4c4c4;
+    text-decoration: line-through;
+  }
+  .score-img {
+    width: 36rpx;
+    height: 36rpx;
+    margin: 0 4rpx;
+  }
+</style>

+ 18 - 10
sheep/components/s-select-seckill-sku/s-select-seckill-sku.vue

@@ -19,8 +19,11 @@
           <view class="goods-title ss-line-2">{{ state.goodsInfo.name }}</view>
           <view class="header-right-bottom ss-flex ss-col-center ss-row-between">
             <!-- 价格 -->
-            <view class="price-text">
-              {{ fen2yuan(state.selectedSku.price || state.goodsInfo.price) }}
+            <view v-if="state.goodsInfo.activity_type === PromotionActivityTypeEnum.POINT.type" class="price-text">
+              {{ getShowPriceText }}
+            </view>
+            <view v-else class="price-text">
+              ¥{{ fen2yuan(state.selectedSku.price || state.goodsInfo.price) }}
             </view>
             <!-- 秒杀价格标签 -->
             <view class="tig ss-flex ss-col-center">
@@ -92,12 +95,15 @@
   import { computed, reactive, watch } from 'vue';
   import sheep from '@/sheep';
   import { convertProductPropertyList, fen2yuan } from '@/sheep/hooks/useGoods';
-  import { min } from 'lodash-es';
+  import { isEmpty, min } from 'lodash-es';
+  import { PromotionActivityTypeEnum } from '@/sheep/util/const';
+
   const emits = defineEmits(['change', 'addCart', 'buy', 'close']);
   const props = defineProps({
     modelValue: {
       type: Object,
-      default() {},
+      default() {
+      },
     },
     show: {
       type: Boolean,
@@ -114,7 +120,14 @@
     selectedSku: {},
     currentPropertyArray: [],
   });
-
+  const getShowPriceText = computed(() => {
+    let priceText = `¥${fen2yuan(state.goodsInfo.price)}`;
+    if (!isEmpty(state.selectedSku)) {
+      const sku = state.selectedSku;
+      priceText = `${sku.point}积分${!sku.pointPrice ? '' : `+¥${fen2yuan(sku.pointPrice)}`}`;
+    }
+    return priceText;
+  });
   const propertyList = convertProductPropertyList(state.goodsInfo.skus);
   // SKU 列表
   const skuList = computed(() => {
@@ -344,11 +357,6 @@
         font-weight: 500;
         color: $red;
         font-family: OPPOSANS;
-
-        &::before {
-          content: '¥';
-          font-size: 24rpx;
-        }
       }
 
       .stock-text {

+ 393 - 335
sheep/components/s-select-sku/s-select-sku.vue

@@ -1,106 +1,139 @@
 <template>
-	<!-- 规格弹窗 -->
-	<su-popup :show="show" round="10" @close="emits('close')">
+  <!-- 规格弹窗 -->
+  <su-popup :show="show" round="10" @close="emits('close')">
     <!-- SKU 信息 -->
-		<view class="ss-modal-box bg-white ss-flex-col">
-			<view class="modal-header ss-flex ss-col-center">
-				<view class="header-left ss-m-r-30">
-					<image class="sku-image" :src="state.selectedSku.picUrl || goodsInfo.picUrl" mode="aspectFill" />
-				</view>
-				<view class="header-right ss-flex-col ss-row-between ss-flex-1">
-					<view class="goods-title ss-line-2">{{ goodsInfo.name }}</view>
-					<view class="header-right-bottom ss-flex ss-col-center ss-row-between">
-						<view class="ss-flex">
-							<view class="price-text">
-								{{ fen2yuan( state.selectedSku.price || goodsInfo.price) }}
-							</view>
-						</view>
-						<view class="stock-text ss-m-l-20">
-							{{ formatStock('exact', state.selectedSku.stock || goodsInfo.stock) }}
-						</view>
-					</view>
-				</view>
-			</view>
+    <view class="ss-modal-box bg-white ss-flex-col">
+      <view class="modal-header ss-flex ss-col-center">
+        <view class="header-left ss-m-r-30">
+          <image
+            class="sku-image"
+            :src="state.selectedSku.picUrl || goodsInfo.picUrl"
+            mode="aspectFill"
+          />
+        </view>
+        <view class="header-right ss-flex-col ss-row-between ss-flex-1">
+          <view class="goods-title ss-line-2">{{ goodsInfo.name }}</view>
+          <view class="header-right-bottom ss-flex ss-col-center ss-row-between">
+            <view class="ss-flex">
+              <view class="price-text">
+                {{
+                  fen2yuan(
+                    state.selectedSku.promotionPrice || state.selectedSku.price || goodsInfo.price,
+                  )
+                }}
+                <text v-if="state.selectedSku.promotionType > 0">
+                  <text class="iconBox" v-if="state.selectedSku.promotionType === 4">
+                    限时优惠
+                  </text>
+                  <text class="iconBox" v-else-if="state.selectedSku.promotionType === 6">
+                    会员价
+                  </text>
+                  <text class="origin-price-text">
+                    {{ fen2yuan(state.selectedSku.price) }}
+                  </text>
+                </text>
+              </view>
+            </view>
+            <view class="stock-text ss-m-l-20">
+              {{ formatStock('exact', state.selectedSku.stock || goodsInfo.stock) }}
+            </view>
+          </view>
+        </view>
+      </view>
 
       <!-- 属性选择 -->
-			<view class="modal-content ss-flex-1">
-				<scroll-view scroll-y="true" class="modal-content-scroll" @touchmove.stop>
-					<view class="sku-item ss-m-b-20" v-for="property in propertyList" :key="property.id">
-						<view class="label-text ss-m-b-20">{{ property.name }}</view>
-						<view class="ss-flex ss-col-center ss-flex-wrap">
-							<button class="ss-reset-button spec-btn" v-for="value in property.values" :class="[
+      <view class="modal-content ss-flex-1">
+        <scroll-view scroll-y="true" class="modal-content-scroll" @touchmove.stop>
+          <view class="sku-item ss-m-b-20" v-for="property in propertyList" :key="property.id">
+            <view class="label-text ss-m-b-20">{{ property.name }}</view>
+            <view class="ss-flex ss-col-center ss-flex-wrap">
+              <button
+                class="ss-reset-button spec-btn"
+                v-for="value in property.values"
+                :class="[
                   {
                     'ui-BG-Main-Gradient': state.currentPropertyArray[property.id] === value.id,
                   },
                   {
                     'disabled-btn': value.disabled === true,
                   },
-                ]" :key="value.id" :disabled="value.disabled === true" @tap="onSelectSku(property.id, value.id)">
-								{{ value.name }}
-							</button>
-						</view>
-					</view>
-					<view class="buy-num-box ss-flex ss-col-center ss-row-between ss-m-b-40">
-						<view class="label-text">购买数量</view>
-						<su-number-box :min="1" :max="state.selectedSku.stock" :step="1"
-                           v-model="state.selectedSku.goods_num" @change="onNumberChange($event)" />
-					</view>
-				</scroll-view>
-			</view>
+                ]"
+                :key="value.id"
+                :disabled="value.disabled === true"
+                @tap="onSelectSku(property.id, value.id)"
+              >
+                {{ value.name }}
+              </button>
+            </view>
+          </view>
+          <view class="buy-num-box ss-flex ss-col-center ss-row-between ss-m-b-40">
+            <view class="label-text">购买数量</view>
+            <su-number-box
+              :min="1"
+              :max="state.selectedSku.stock"
+              :step="1"
+              v-model="state.selectedSku.goods_num"
+              @change="onNumberChange($event)"
+            />
+          </view>
+        </scroll-view>
+      </view>
 
       <!-- 操作区 -->
-			<view class="modal-footer border-top">
-				<view class="buy-box ss-flex ss-col-center ss-flex ss-col-center ss-row-center">
-					<button class="ss-reset-button add-btn ui-Shadow-Main" @tap="onAddCart">加入购物车</button>
-					<button class="ss-reset-button buy-btn ui-Shadow-Main" @tap="onBuy">立即购买</button>
-				</view>
-			</view>
-		</view>
-	</su-popup>
+      <view class="modal-footer border-top">
+        <view class="buy-box ss-flex ss-col-center ss-flex ss-col-center ss-row-center">
+          <button class="ss-reset-button add-btn ui-Shadow-Main" @tap="onAddCart"
+            >加入购物车</button
+          >
+          <button class="ss-reset-button buy-btn ui-Shadow-Main" @tap="onBuy">立即购买</button>
+        </view>
+      </view>
+    </view>
+  </su-popup>
 </template>
 
 <script setup>
-	import { computed, reactive, watch } from 'vue';
-	import sheep from '@/sheep';
+  import { computed, reactive, watch } from 'vue';
+  import sheep from '@/sheep';
   import { formatStock, convertProductPropertyList, fen2yuan } from '@/sheep/hooks/useGoods';
 
-	const emits = defineEmits(['change', 'addCart', 'buy', 'close']);
-	const props = defineProps({
-		goodsInfo: {
-			type: Object,
-			default () {},
-		},
-		show: {
-			type: Boolean,
-			default: false,
-		}
-	});
-
-	const state = reactive({
-		selectedSku: {}, // 选中的 SKU
-		currentPropertyArray: [], // 当前选中的属性,实际是个 Map。key 是 property 编号,value 是 value 编号
-	});
-
-	const propertyList = convertProductPropertyList(props.goodsInfo.skus);
-
-	// SKU 列表
-	const skuList = computed(() => {
-		let skuPrices = props.goodsInfo.skus;
+  const emits = defineEmits(['change', 'addCart', 'buy', 'close']);
+  const props = defineProps({
+    goodsInfo: {
+      type: Object,
+      default() {},
+    },
+    show: {
+      type: Boolean,
+      default: false,
+    },
+  });
+
+  const state = reactive({
+    selectedSku: {}, // 选中的 SKU
+    currentPropertyArray: [], // 当前选中的属性,实际是个 Map。key 是 property 编号,value 是 value 编号
+  });
+
+  const propertyList = convertProductPropertyList(props.goodsInfo.skus);
+  // SKU 列表
+  const skuList = computed(() => {
+    let skuPrices = props.goodsInfo.skus;
     for (let price of skuPrices) {
-      price.value_id_array = price.properties.map((item) => item.valueId)
+      price.value_id_array = price.properties.map((item) => item.valueId);
     }
-		return skuPrices;
-	});
-
-	watch(
-		() => state.selectedSku,
-		(newVal) => {
-			emits('change', newVal);
-		}, {
-			immediate: true, // 立即执行
-			deep: true, // 深度监听
-		},
-	);
+    return skuPrices;
+  });
+
+  watch(
+    () => state.selectedSku,
+    (newVal) => {
+      emits('change', newVal);
+    },
+    {
+      immediate: true, // 立即执行
+      deep: true, // 深度监听
+    },
+  );
 
   // 输入框改变数量
   function onNumberChange(e) {
@@ -110,21 +143,21 @@
   }
 
   // 加入购物车
-	function onAddCart() {
-		if (state.selectedSku.id <= 0) {
+  function onAddCart() {
+    if (state.selectedSku.id <= 0) {
       sheep.$helper.toast('请选择规格');
       return;
-		}
+    }
     if (state.selectedSku.stock <= 0) {
       sheep.$helper.toast('库存不足');
       return;
     }
 
     emits('addCart', state.selectedSku);
-	}
+  }
 
   // 立即购买
-	function onBuy() {
+  function onBuy() {
     if (state.selectedSku.id <= 0) {
       sheep.$helper.toast('请选择规格');
       return;
@@ -134,273 +167,298 @@
       return;
     }
     emits('buy', state.selectedSku);
-	}
+  }
 
-	// 改变禁用状态:计算每个 property 属性值的按钮,是否禁用
-	function changeDisabled(isChecked = false, propertyId = 0, valueId = 0) {
+  // 改变禁用状态:计算每个 property 属性值的按钮,是否禁用
+  function changeDisabled(isChecked = false, propertyId = 0, valueId = 0) {
     let newSkus = []; // 所有可以选择的 sku 数组
-		if (isChecked) {
-			// 情况一:选中 property
-			// 获得当前点击选中 property 的、所有可用 SKU
-			for (let price of skuList.value) {
-				if (price.stock <= 0) {
-					continue;
-				}
-				if (price.value_id_array.indexOf(valueId) >= 0) {
-					newSkus.push(price);
-				}
-			}
-		} else {
-			// 情况二:取消选中 property
-			// 当前所选 property 下,所有可以选择的 SKU
-			newSkus = getCanUseSkuList();
-		}
-
-		// 所有存在并且有库存未选择的 SKU 的 value 属性值 id
-		let noChooseValueIds = [];
-		for (let price of newSkus) {
-			noChooseValueIds = noChooseValueIds.concat(price.value_id_array);
-		}
-		noChooseValueIds = Array.from(new Set(noChooseValueIds)); // 去重
-
-		if (isChecked) {
-			// 去除当前选中的 value 属性值 id
-			let index = noChooseValueIds.indexOf(valueId);
-			noChooseValueIds.splice(index, 1);
-		} else {
-			// 循环去除当前已选择的 value 属性值 id
-			state.currentPropertyArray.forEach((currentPropertyId) => {
-				if (currentPropertyId.toString() !== '') {
+    if (isChecked) {
+      // 情况一:选中 property
+      // 获得当前点击选中 property 的、所有可用 SKU
+      for (let price of skuList.value) {
+        if (price.stock <= 0) {
+          continue;
+        }
+        if (price.value_id_array.indexOf(valueId) >= 0) {
+          newSkus.push(price);
+        }
+      }
+    } else {
+      // 情况二:取消选中 property
+      // 当前所选 property 下,所有可以选择的 SKU
+      newSkus = getCanUseSkuList();
+    }
+
+    // 所有存在并且有库存未选择的 SKU 的 value 属性值 id
+    let noChooseValueIds = [];
+    for (let price of newSkus) {
+      noChooseValueIds = noChooseValueIds.concat(price.value_id_array);
+    }
+    noChooseValueIds = Array.from(new Set(noChooseValueIds)); // 去重
+
+    if (isChecked) {
+      // 去除当前选中的 value 属性值 id
+      let index = noChooseValueIds.indexOf(valueId);
+      noChooseValueIds.splice(index, 1);
+    } else {
+      // 循环去除当前已选择的 value 属性值 id
+      state.currentPropertyArray.forEach((currentPropertyId) => {
+        if (currentPropertyId.toString() !== '') {
           return;
-				}
+        }
         // currentPropertyId 为空是反选 填充的
         let index = noChooseValueIds.indexOf(currentPropertyId);
         if (index >= 0) {
           // currentPropertyId 存在于 noChooseValueIds
           noChooseValueIds.splice(index, 1);
         }
-			});
-		}
+      });
+    }
 
     // 当前已选择的 property 数组
-		let choosePropertyIds = [];
-		if (!isChecked) {
-			// 当前已选择的 property
-			state.currentPropertyArray.forEach((currentPropertyId, currentValueId) => {
-				if (currentPropertyId !== '') {
-					// currentPropertyId 为空是反选 填充的
-					choosePropertyIds.push(currentValueId);
-				}
-			});
-		} else {
-			// 当前点击选择的 property
-			choosePropertyIds = [propertyId];
-		}
+    let choosePropertyIds = [];
+    if (!isChecked) {
+      // 当前已选择的 property
+      state.currentPropertyArray.forEach((currentPropertyId, currentValueId) => {
+        if (currentPropertyId !== '') {
+          // currentPropertyId 为空是反选 填充的
+          choosePropertyIds.push(currentValueId);
+        }
+      });
+    } else {
+      // 当前点击选择的 property
+      choosePropertyIds = [propertyId];
+    }
 
     for (let propertyIndex in propertyList) {
-			// 当前点击的 property、或者取消选择时候,已选中的 property 不进行处理
-			if (choosePropertyIds.indexOf(propertyList[propertyIndex]['id']) >= 0) {
-				continue;
-			}
+      // 当前点击的 property、或者取消选择时候,已选中的 property 不进行处理
+      if (choosePropertyIds.indexOf(propertyList[propertyIndex]['id']) >= 0) {
+        continue;
+      }
       // 如果当前 property id 不存在于有库存的 SKU 中,则禁用
       for (let valueIndex in propertyList[propertyIndex]['values']) {
-				propertyList[propertyIndex]['values'][valueIndex]['disabled'] =
+        propertyList[propertyIndex]['values'][valueIndex]['disabled'] =
           noChooseValueIds.indexOf(propertyList[propertyIndex]['values'][valueIndex]['id']) < 0; // true 禁用 or false 不禁用
-			}
-		}
-	}
-
-	// 当前所选属性下,获取所有有库存的 SKU 们
-	function getCanUseSkuList() {
-		let newSkus = [];
-		for (let sku of skuList.value) {
-			if (sku.stock <= 0) {
-				continue;
-			}
+      }
+    }
+  }
+
+  // 当前所选属性下,获取所有有库存的 SKU 们
+  function getCanUseSkuList() {
+    let newSkus = [];
+    for (let sku of skuList.value) {
+      if (sku.stock <= 0) {
+        continue;
+      }
       let isOk = true;
       state.currentPropertyArray.forEach((propertyId) => {
-				// propertyId 不为空,并且,这个 条 sku 没有被选中,则排除
-				if (propertyId.toString() !== '' && sku.value_id_array.indexOf(propertyId) < 0) {
-					isOk = false;
-				}
-			});
-			if (isOk) {
-				newSkus.push(sku);
-			}
-		}
-		return newSkus;
-	}
-
-	// 选择规格
-	function onSelectSku(propertyId, valueId) {
-		// 清空已选择
-		let isChecked = true; // 选中 or 取消选中
-		if (state.currentPropertyArray[propertyId] !== undefined && state.currentPropertyArray[propertyId] === valueId) {
-			// 点击已被选中的,删除并填充 ''
-			isChecked = false;
-			state.currentPropertyArray.splice(propertyId, 1, '');
-		} else {
-			// 选中
-			state.currentPropertyArray[propertyId] = valueId;
-		}
+        // propertyId 不为空,并且,这个 条 sku 没有被选中,则排除
+        if (propertyId.toString() !== '' && sku.value_id_array.indexOf(propertyId) < 0) {
+          isOk = false;
+        }
+      });
+      if (isOk) {
+        newSkus.push(sku);
+      }
+    }
+    return newSkus;
+  }
+
+  // 选择规格
+  function onSelectSku(propertyId, valueId) {
+    // 清空已选择
+    let isChecked = true; // 选中 or 取消选中
+    if (
+      state.currentPropertyArray[propertyId] !== undefined &&
+      state.currentPropertyArray[propertyId] === valueId
+    ) {
+      // 点击已被选中的,删除并填充 ''
+      isChecked = false;
+      state.currentPropertyArray.splice(propertyId, 1, '');
+    } else {
+      // 选中
+      state.currentPropertyArray[propertyId] = valueId;
+    }
 
     // 选中的 property 大类
-		let choosePropertyId = [];
-		state.currentPropertyArray.forEach((currentPropertyId) => {
-			if (currentPropertyId !== '') {
-				// currentPropertyId 为空是反选 填充的
-				choosePropertyId.push(currentPropertyId);
-			}
-		});
-
-		// 当前所选 property 下,所有可以选择的 SKU 们
-		let newSkuList = getCanUseSkuList();
-
-		// 判断所有 property 大类是否选择完成
-		if (choosePropertyId.length === propertyList.length && newSkuList.length) {
-			newSkuList[0].goods_num = state.selectedSku.goods_num || 1;
-			state.selectedSku = newSkuList[0];
-		} else {
-			state.selectedSku = {};
-		}
-
-		// 改变 property 禁用状态
-		changeDisabled(isChecked, propertyId, valueId);
-	}
-
-	changeDisabled(false);
+    let choosePropertyId = [];
+    state.currentPropertyArray.forEach((currentPropertyId) => {
+      if (currentPropertyId !== '') {
+        // currentPropertyId 为空是反选 填充的
+        choosePropertyId.push(currentPropertyId);
+      }
+    });
+
+    // 当前所选 property 下,所有可以选择的 SKU 们
+    let newSkuList = getCanUseSkuList();
+
+    // 判断所有 property 大类是否选择完成
+    if (choosePropertyId.length === propertyList.length && newSkuList.length) {
+      newSkuList[0].goods_num = state.selectedSku.goods_num || 1;
+      state.selectedSku = newSkuList[0];
+    } else {
+      state.selectedSku = {};
+    }
+
+    // 改变 property 禁用状态
+    changeDisabled(isChecked, propertyId, valueId);
+  }
+
+  changeDisabled(false);
   // TODO 芋艿:待讨论的优化点:1)单规格,要不要默认选中;2)默认要不要选中第一个规格
 </script>
 
 <style lang="scss" scoped>
-	// 购买
-	.buy-box {
-		padding: 10rpx 0;
-
-		.add-btn {
-			width: 356rpx;
-			height: 80rpx;
-			border-radius: 40rpx 0 0 40rpx;
-			background-color: var(--ui-BG-Main-light);
-			color: var(--ui-BG-Main);
-		}
-
-		.buy-btn {
-			width: 356rpx;
-			height: 80rpx;
-			border-radius: 0 40rpx 40rpx 0;
-			background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
-			color: #fff;
-		}
-
-		.score-btn {
-			width: 100%;
-			margin: 0 20rpx;
-			height: 80rpx;
-			border-radius: 40rpx;
-			background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
-			color: #fff;
-		}
-	}
-
-	.ss-modal-box {
-		border-radius: 30rpx 30rpx 0 0;
-		max-height: 1000rpx;
-
-		.modal-header {
-			position: relative;
-			padding: 80rpx 20rpx 40rpx;
-
-			.sku-image {
-				width: 160rpx;
-				height: 160rpx;
-				border-radius: 10rpx;
-			}
-
-			.header-right {
-				height: 160rpx;
-			}
-
-			.close-icon {
-				position: absolute;
-				top: 10rpx;
-				right: 20rpx;
-				font-size: 46rpx;
-				opacity: 0.2;
-			}
-
-			.goods-title {
-				font-size: 28rpx;
-				font-weight: 500;
-				line-height: 42rpx;
-			}
-
-			.score-img {
-				width: 36rpx;
-				height: 36rpx;
-				margin: 0 4rpx;
-			}
-
-			.score-text {
-				font-size: 30rpx;
-				font-weight: 500;
-				color: $red;
-				font-family: OPPOSANS;
-			}
-
-			.price-text {
-				font-size: 30rpx;
-				font-weight: 500;
-				color: $red;
-				font-family: OPPOSANS;
-
-				&::before {
-					content: '¥';
-					font-size: 30rpx;
-					font-weight: 500;
-					color: $red;
-				}
-			}
-
-			.stock-text {
-				font-size: 26rpx;
-				color: #999999;
-			}
-		}
-
-		.modal-content {
-			padding: 0 20rpx;
-
-			.modal-content-scroll {
-				max-height: 600rpx;
-
-				.label-text {
-					font-size: 26rpx;
-					font-weight: 500;
-				}
-
-				.buy-num-box {
-					height: 100rpx;
-				}
-
-				.spec-btn {
-					height: 60rpx;
-					min-width: 100rpx;
-					padding: 0 30rpx;
-					background: #f4f4f4;
-					border-radius: 30rpx;
-					color: #434343;
-					font-size: 26rpx;
-					margin-right: 10rpx;
-					margin-bottom: 10rpx;
-				}
-
-				.disabled-btn {
-					font-weight: 400;
-					color: #c6c6c6;
-					background: #f8f8f8;
-				}
-			}
-		}
-	}
-</style>
+  // 购买
+  .buy-box {
+    padding: 10rpx 0;
+
+    .add-btn {
+      width: 356rpx;
+      height: 80rpx;
+      border-radius: 40rpx 0 0 40rpx;
+      background-color: var(--ui-BG-Main-light);
+      color: var(--ui-BG-Main);
+    }
+
+    .buy-btn {
+      width: 356rpx;
+      height: 80rpx;
+      border-radius: 0 40rpx 40rpx 0;
+      background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
+      color: #fff;
+    }
+
+    .score-btn {
+      width: 100%;
+      margin: 0 20rpx;
+      height: 80rpx;
+      border-radius: 40rpx;
+      background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
+      color: #fff;
+    }
+  }
+
+  .ss-modal-box {
+    border-radius: 30rpx 30rpx 0 0;
+    max-height: 1000rpx;
+
+    .modal-header {
+      position: relative;
+      padding: 80rpx 20rpx 40rpx;
+
+      .sku-image {
+        width: 160rpx;
+        height: 160rpx;
+        border-radius: 10rpx;
+      }
+
+      .header-right {
+        height: 160rpx;
+      }
+
+      .close-icon {
+        position: absolute;
+        top: 10rpx;
+        right: 20rpx;
+        font-size: 46rpx;
+        opacity: 0.2;
+      }
+
+      .goods-title {
+        font-size: 28rpx;
+        font-weight: 500;
+        line-height: 42rpx;
+      }
+
+      .score-img {
+        width: 36rpx;
+        height: 36rpx;
+        margin: 0 4rpx;
+      }
+
+      .score-text {
+        font-size: 30rpx;
+        font-weight: 500;
+        color: $red;
+        font-family: OPPOSANS;
+      }
+
+      .price-text {
+        font-size: 30rpx;
+        font-weight: 500;
+        color: $red;
+        font-family: OPPOSANS;
+
+        &::before {
+          content: '¥';
+          font-size: 30rpx;
+          font-weight: 500;
+          color: $red;
+        }
+      }
+
+      .stock-text {
+        font-size: 26rpx;
+        color: #999999;
+      }
+    }
+
+    .modal-content {
+      padding: 0 20rpx;
+
+      .modal-content-scroll {
+        max-height: 600rpx;
+
+        .label-text {
+          font-size: 26rpx;
+          font-weight: 500;
+        }
+
+        .buy-num-box {
+          height: 100rpx;
+        }
+
+        .spec-btn {
+          height: 60rpx;
+          min-width: 100rpx;
+          padding: 0 30rpx;
+          background: #f4f4f4;
+          border-radius: 30rpx;
+          color: #434343;
+          font-size: 26rpx;
+          margin-right: 10rpx;
+          margin-bottom: 10rpx;
+        }
+
+        .disabled-btn {
+          font-weight: 400;
+          color: #c6c6c6;
+          background: #f8f8f8;
+        }
+      }
+    }
+  }
+
+  .iconBox {
+    width: fit-content;
+    height: fit-content;
+    padding: 2rpx 10rpx;
+    background-color: rgb(255, 242, 241);
+    color: #ff2621;
+    font-size: 24rpx;
+    margin-left: 5rpx;
+  }
+
+  .origin-price-text {
+    font-size: 26rpx;
+    font-weight: 400;
+    text-decoration: line-through;
+    color: $gray-c;
+    font-family: OPPOSANS;
+
+    &::before {
+      content: '¥';
+    }
+  }
+</style>

+ 158 - 48
sheep/hooks/useGoods.js

@@ -11,7 +11,7 @@ import { formatDate } from '@/sheep/util';
  */
 export function formatSales(type, num) {
   let prefix = type !== 'exact' && num < 10 ? '销量' : '已售';
-  return formatNum(prefix, type, num)
+  return formatNum(prefix, type, num);
 }
 
 /**
@@ -21,10 +21,9 @@ export function formatSales(type, num) {
  * @return {string} 格式化后的销量字符串
  */
 export function formatExchange(type, num) {
-  return formatNum('已兑换', type, num)
+  return formatNum('已兑换', type, num);
 }
 
-
 /**
  * 格式化库存
  * @param {'exact' | any} type 格式类型:exact=精确值,其它=大致数量
@@ -32,7 +31,7 @@ export function formatExchange(type, num) {
  * @return {string} 格式化后的销量字符串
  */
 export function formatStock(type, num) {
-  return formatNum('库存', type, num)
+  return formatNum('库存', type, num);
 }
 
 /**
@@ -43,7 +42,7 @@ export function formatStock(type, num) {
  * @return {string} 格式化后的销量字符串
  */
 export function formatNum(prefix, type, num) {
-  num = (num || 0);
+  num = num || 0;
   // 情况一:精确数值
   if (type === 'exact') {
     return prefix + num;
@@ -67,7 +66,7 @@ export function formatPrice(e) {
 }
 
 // 视频格式后缀列表
-const VIDEO_SUFFIX_LIST = ['.avi', '.mp4']
+const VIDEO_SUFFIX_LIST = ['.avi', '.mp4'];
 
 /**
  * 转换商品轮播的链接列表:根据链接的后缀,判断是视频链接还是图片链接
@@ -76,12 +75,19 @@ const VIDEO_SUFFIX_LIST = ['.avi', '.mp4']
  * @return {{src: string, type: 'video' | 'image' }[]}  转换后的链接列表
  */
 export function formatGoodsSwiper(urlList) {
-  return urlList?.filter(url => url).map((url, key) => {
-    const isVideo = VIDEO_SUFFIX_LIST.some(suffix => url.includes(suffix));
-    const type = isVideo ? 'video' : 'image'
-    const src = $url.cdn(url);
-    return { type, src }
-  }) || [];
+  return (
+    urlList
+      ?.filter((url) => url)
+      .map((url, key) => {
+        const isVideo = VIDEO_SUFFIX_LIST.some((suffix) => url.includes(suffix));
+        const type = isVideo ? 'video' : 'image';
+        const src = $url.cdn(url);
+        return {
+          type,
+          src,
+        };
+      }) || []
+  );
 }
 
 /**
@@ -94,9 +100,7 @@ export function formatOrderColor(order) {
   if (order.status === 0) {
     return 'info-color';
   }
-  if (order.status === 10
-    || order.status === 20
-    || (order.status === 30 && !order.commentStatus)) {
+  if (order.status === 10 || order.status === 20 || (order.status === 30 && !order.commentStatus)) {
     return 'warning-color';
   }
   if (order.status === 30 && order.commentStatus) {
@@ -139,7 +143,7 @@ export function formatOrderStatus(order) {
  */
 export function formatOrderStatusDescription(order) {
   if (order.status === 0) {
-    return `请在 ${ formatDate(order.payExpireTime) } 前完成支付`;
+    return `请在 ${formatDate(order.payExpireTime)} 前完成支付`;
   }
   if (order.status === 10) {
     return '商家未发货,请耐心等待';
@@ -162,24 +166,30 @@ export function formatOrderStatusDescription(order) {
  * @param order 订单
  */
 export function handleOrderButtons(order) {
-  order.buttons = []
-  if (order.type === 3) { // 查看拼团
+  order.buttons = [];
+  if (order.type === 3) {
+    // 查看拼团
     order.buttons.push('combination');
   }
-  if (order.status === 20) { // 确认收货
+  if (order.status === 20) {
+    // 确认收货
     order.buttons.push('confirm');
   }
-  if (order.logisticsId > 0) { // 查看物流
+  if (order.logisticsId > 0) {
+    // 查看物流
     order.buttons.push('express');
   }
-  if (order.status === 0) { // 取消订单 / 发起支付
+  if (order.status === 0) {
+    // 取消订单 / 发起支付
     order.buttons.push('cancel');
     order.buttons.push('pay');
   }
-  if (order.status === 30 && !order.commentStatus) { // 发起评价
+  if (order.status === 30 && !order.commentStatus) {
+    // 发起评价
     order.buttons.push('comment');
   }
-  if (order.status === 40) { // 删除订单
+  if (order.status === 40) {
+    // 删除订单
     order.buttons.push('delete');
   }
 }
@@ -257,10 +267,12 @@ export function formatAfterSaleStatusDescription(afterSale) {
  */
 export function handleAfterSaleButtons(afterSale) {
   afterSale.buttons = [];
-  if ([10, 20, 30].includes(afterSale.status)) { // 取消订单
+  if ([10, 20, 30].includes(afterSale.status)) {
+    // 取消订单
     afterSale.buttons.push('cancel');
   }
-  if (afterSale.status === 20) { // 退货信息
+  if (afterSale.status === 20) {
+    // 退货信息
     afterSale.buttons.push('delivery');
   }
 }
@@ -324,7 +336,28 @@ function getDayjsTime(time) {
  * @returns {string} 元,例如说 1.00 元
  */
 export function fen2yuan(price) {
-  return (price / 100.0).toFixed(2)
+  return (price / 100.0).toFixed(2);
+}
+
+/**
+ * 将分转成元
+ *
+ * 如果没有小数点,则不展示小数点部分
+ *
+ * @param price 分,例如说 100 分
+ * @returns {string} 元,例如说 1 元
+ */
+export function fen2yuanSimple(price) {
+  return fen2yuan(price).replace(/\.?0+$/, '');
+}
+
+/**
+ * 将折扣百分比转化为“打x者”的 x 部分
+ *
+ * @param discountPercent
+ */
+export function formatDiscountPercent(discountPercent) {
+  return (discountPercent / 10.0).toFixed(1).replace(/\.?0+$/, '');
 }
 
 /**
@@ -345,45 +378,122 @@ export function convertProductPropertyList(skus) {
   let result = [];
   for (const sku of skus) {
     if (!sku.properties) {
-      continue
+      continue;
     }
     for (const property of sku.properties) {
       // ① 先处理属性
-      let resultProperty = result.find(item => item.id === property.propertyId)
+      let resultProperty = result.find((item) => item.id === property.propertyId);
       if (!resultProperty) {
         resultProperty = {
           id: property.propertyId,
           name: property.propertyName,
-          values: []
-        }
-        result.push(resultProperty)
+          values: [],
+        };
+        result.push(resultProperty);
       }
       // ② 再处理属性值
-      let resultValue = resultProperty.values.find(item => item.id === property.valueId)
+      let resultValue = resultProperty.values.find((item) => item.id === property.valueId);
       if (!resultValue) {
         resultProperty.values.push({
           id: property.valueId,
-          name: property.valueName
-        })
+          name: property.valueName,
+        });
       }
     }
   }
   return result;
 }
 
-/**
- * 格式化满减送活动的规则
- *
- * @param activity 活动信息
- * @param rule 优惠规格
- * @returns {string} 规格字符串
- */
-export function formatRewardActivityRule(activity, rule) {
-  if (activity.conditionType === 10) {
-    return `满 ${fen2yuan(rule.limit)} 元减 ${fen2yuan(rule.discountPrice)} 元`;
-  }
-  if (activity.conditionType === 20) {
-    return `满 ${rule.limit} 件减 ${fen2yuan(rule.discountPrice)} 元`;
+export function appendSettlementProduct(spus, settlementInfos) {
+  if (!settlementInfos || settlementInfos.length === 0) {
+    return;
+  }
+  for (const spu of spus) {
+    const settlementInfo = settlementInfos.find((info) => info.spuId === spu.id);
+    if (!settlementInfo) {
+      return;
+    }
+    // 选择价格最小的 SKU 设置到 SPU 上
+    const settlementSku = settlementInfo.skus
+      .filter((sku) => sku.promotionPrice > 0)
+      .reduce((prev, curr) => (prev.promotionPrice < curr.promotionPrice ? prev : curr));
+    if (settlementSku) {
+      spu.promotionType = settlementSku.promotionType;
+      spu.promotionPrice = settlementSku.promotionPrice;
+    }
+    // 设置【满减送】活动
+    if (settlementInfo.rewardActivity) {
+      spu.rewardActivity = settlementInfo.rewardActivity;
+    }
   }
-  return '';
+}
+
+// 获得满减送活动的规则描述(group)
+export function getRewardActivityRuleGroupDescriptions(activity) {
+  if (!activity || !activity.rules || activity.rules.length === 0) {
+    return [];
+  }
+  const result = [
+    { name: '满减', values: [] },
+    { name: '赠品', values: [] },
+    { name: '包邮', values: [] },
+  ];
+  activity.rules.forEach((rule) => {
+    const conditionTypeStr =
+      activity.conditionType === 10 ? `满 ${fen2yuanSimple(rule.limit)} 元` : `满 ${rule.limit} 件`;
+    // 满减
+    if (rule.limit) {
+      result[0].values.push(`${conditionTypeStr} 减 ${fen2yuanSimple(rule.discountPrice)} 元`);
+    }
+    // 赠品
+    if (rule.point || (rule.giveCouponTemplateCounts && rule.giveCouponTemplateCounts.length > 0)) {
+      let tips = [];
+      if (rule.point) {
+        tips.push(`送 ${rule.point} 积分`);
+      }
+      if (rule.giveCouponTemplateCounts && rule.giveCouponTemplateCounts.length > 0) {
+        tips.push(`送 ${rule.giveCouponTemplateCounts.length} 张优惠券`);
+      }
+      result[1].values.push(`${conditionTypeStr} ${tips.join('、')}`);
+    }
+    // 包邮
+    if (rule.freeDelivery) {
+      result[2].values.push(`${conditionTypeStr} 包邮`);
+    }
+  });
+  // 移除 values 为空的元素
+  result.forEach((item) => {
+    if (item.values.length === 0) {
+      result.splice(result.indexOf(item), 1);
+    }
+  });
+  return result;
+}
+
+// 获得满减送活动的规则描述(item)
+export function getRewardActivityRuleItemDescriptions(activity) {
+  if (!activity || !activity.rules || activity.rules.length === 0) {
+    return [];
+  }
+  const result = [];
+  activity.rules.forEach((rule) => {
+    const conditionTypeStr =
+      activity.conditionType === 10 ? `满${fen2yuanSimple(rule.limit)}元` : `满${rule.limit}件`;
+    // 满减
+    if (rule.limit) {
+      result.push(`${conditionTypeStr}减${fen2yuanSimple(rule.discountPrice)}元`);
+    }
+    // 赠品
+    if (rule.point) {
+      result.push(`${conditionTypeStr}送${rule.point}积分`);
+    }
+    if (rule.giveCouponTemplateCounts && rule.giveCouponTemplateCounts.length > 0) {
+      result.push(`${conditionTypeStr}送${rule.giveCouponTemplateCounts.length}张优惠券`);
+    }
+    // 包邮
+    if (rule.freeDelivery) {
+      result.push(`${conditionTypeStr}包邮`);
+    }
+  });
+  return result;
 }

+ 64 - 48
sheep/platform/pay.js

@@ -35,7 +35,7 @@ export default class SheepPay {
         },
         mock: () => {
           this.mockPay();
-        }
+        },
       },
       WechatMiniProgram: {
         wechat: () => {
@@ -49,7 +49,7 @@ export default class SheepPay {
         },
         mock: () => {
           this.mockPay();
-        }
+        },
       },
       App: {
         wechat: () => {
@@ -63,7 +63,7 @@ export default class SheepPay {
         },
         mock: () => {
           this.mockPay();
-        }
+        },
       },
       H5: {
         wechat: () => {
@@ -77,7 +77,7 @@ export default class SheepPay {
         },
         mock: () => {
           this.mockPay();
-        }
+        },
       },
     };
     return payAction[sheep.$platform.name][this.payment]();
@@ -89,7 +89,7 @@ export default class SheepPay {
       let data = {
         id: this.id,
         channelCode: channel,
-        channelExtras: {}
+        channelExtras: {},
       };
       // 特殊逻辑:微信公众号、小程序支付时,必须传入 openid
       if (['wx_pub', 'wx_lite'].includes(channel)) {
@@ -108,8 +108,11 @@ export default class SheepPay {
         // 失败时
         if (res.code !== 0 && res.msg.indexOf('无效的openid') >= 0) {
           // 特殊逻辑:微信公众号、小程序支付时,必须传入 openid 不正确的情况
-          if (res.msg.indexOf('无效的openid') >= 0 // 获取的 openid 不正确时,或者随便输入了个 openid
-            || res.msg.indexOf('下单账号与支付账号不一致') >= 0) { // https://developers.weixin.qq.com/community/develop/doc/00008c53c347804beec82aed051c00
+          if (
+            res.msg.indexOf('无效的openid') >= 0 || // 获取的 openid 不正确时,或者随便输入了个 openid
+            res.msg.indexOf('下单账号与支付账号不一致') >= 0
+          ) {
+            // https://developers.weixin.qq.com/community/develop/doc/00008c53c347804beec82aed051c00
             this.bindWeixin();
           }
         }
@@ -133,30 +136,34 @@ export default class SheepPay {
       },
       fail: (error) => {
         if (error.errMsg.indexOf('chooseWXPay:没有此SDK或暂不支持此SDK模拟') >= 0) {
-          sheep.$helper.toast('发起微信支付失败,原因:可能是微信开发者工具不支持,建议使用微信打开网页后支付');
-          return
+          sheep.$helper.toast(
+            '发起微信支付失败,原因:可能是微信开发者工具不支持,建议使用微信打开网页后支付',
+          );
+          return;
         }
         this.payResult('fail');
       },
     });
   }
 
-  // 浏览器微信 H5 支付 TODO 芋艿:待接入
+  // 浏览器微信 H5 支付 TODO 芋艿:待接入(注意:H5 支付是给普通浏览器,不是微信公众号的支付,绝大多数人用不到,可以忽略)
   async wechatWapPay() {
     const { error, data } = await this.prepay();
     if (error === 0) {
-      const redirect_url = `${getRootUrl()}pages/pay/result?id=${this.id}&payment=${this.payment}&orderType=${this.orderType}`;
+      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 芋艿:待接入
+  // 支付链接(支付宝 wap 支付)
   async redirectPay() {
-    let { error, data } = await this.prepay();
-    if (error === 0) {
-      const redirect_url = `${getRootUrl()}pages/pay/result?id=${this.id}&payment=${this.payment}&orderType=${this.orderType}`;
-      location.href = data.pay_data + encodeURIComponent(redirect_url);
+    let { code, data } = await this.prepay('alipay_wap');
+    if (code !== 0) {
+      return;
     }
+    location.href = data.displayContent;
   }
 
   // #endif
@@ -202,26 +209,26 @@ export default class SheepPay {
     code === 0 && this.payResult('success');
   }
 
-  // 支付宝复制链接支付  TODO 芋艿:待接入
+  // 支付宝复制链接支付(通过支付宝 wap 支付实现)
   async copyPayLink() {
-    let that = this;
-    let { error, data } = await this.prepay();
-    if (error === 0) {
-      // 引入showModal 点击确认 复制链接;
-      uni.showModal({
-        title: '支付宝支付',
-        content: '复制链接到外部浏览器',
-        confirmText: '复制链接',
-        success: (res) => {
-          if (res.confirm) {
-            sheep.$helper.copyText(data.pay_data);
-          }
-        },
-      });
+    let { code, data } = await this.prepay('alipay_wap');
+    if (code !== 0) {
+      return;
     }
+    // 引入 showModal 点击确认:复制链接;
+    uni.showModal({
+      title: '支付宝支付',
+      content: '复制链接到外部浏览器',
+      confirmText: '复制链接',
+      success: (res) => {
+        if (res.confirm) {
+          sheep.$helper.copyText(data.displayContent);
+        }
+      },
+    });
   }
 
-  // 支付宝支付  TODO 芋艿:待接入
+  // 支付宝支付(App) TODO 芋艿:待接入【暂时没打包 app,所以没接入,一般人用不到】
   async alipay() {
     let that = this;
     const { error, data } = await this.prepay();
@@ -243,7 +250,7 @@ export default class SheepPay {
     }
   }
 
-  // 微信支付  TODO 芋艿:待接入
+  // 微信支付(App)  TODO 芋艿:待接入:待接入【暂时没打包 app,所以没接入,一般人用不到】
   async wechatAppPay() {
     let that = this;
     let { error, data } = await this.prepay();
@@ -263,11 +270,7 @@ export default class SheepPay {
 
   // 支付结果跳转,success:成功,fail:失败
   payResult(resultType) {
-    sheep.$router.redirect('/pages/pay/result', {
-      id: this.id,
-      orderType: this.orderType,
-      payState: resultType
-    });
+    goPayResult(this.id, this.orderType, resultType);
   }
 
   // 引导绑定微信
@@ -282,7 +285,6 @@ export default class SheepPay {
       },
     });
   }
-
 }
 
 export function getPayMethods(channels) {
@@ -316,23 +318,28 @@ export function getPayMethods(channels) {
       title: '模拟支付',
       value: 'mock',
       disabled: true,
-    }
+    },
   ];
-  const platform = sheep.$platform.name
+  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'))) {
+  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')) {
+  if (
+    (platform === 'H5' && channels.includes('alipay_wap')) ||
+    (platform === 'WechatOfficialAccount' && channels.includes('alipay_wap')) ||
+    (platform === 'WechatMiniProgram' && channels.includes('alipay_wap')) ||
+    (platform === 'App' && channels.includes('alipay_app'))
+  ) {
     alipayMethod.disabled = false;
   }
   // 3. 处理【余额支付】
@@ -347,4 +354,13 @@ export function getPayMethods(channels) {
     mockMethod.disabled = false;
   }
   return payMethods;
-}
+}
+
+// 支付结果跳转,success:成功,fail:失败
+export function goPayResult(id, orderType, resultType) {
+  sheep.$router.redirect('/pages/pay/result', {
+    id,
+    orderType,
+    payState: resultType,
+  });
+}

+ 71 - 49
sheep/util/const.js

@@ -33,78 +33,100 @@ export const getTerminal = () => {
 
 // ========== MALL - 营销模块 ==========
 
-import dayjs from "dayjs";
+import dayjs from 'dayjs';
 
 /**
  * 优惠类型枚举
  */
 export const PromotionDiscountTypeEnum = {
-    PRICE: {
-        type: 1,
-        name: '满减'
-    },
-    PERCENT: {
-        type: 2,
-        name: '折扣'
-    }
-}
+  PRICE: {
+    type: 1,
+    name: '满减',
+  },
+  PERCENT: {
+    type: 2,
+    name: '折扣',
+  },
+};
 
 /**
  * 优惠劵模板的有限期类型的枚举
  */
 export const CouponTemplateValidityTypeEnum = {
-    DATE: {
-        type: 1,
-        name: '固定日期可用'
-    },
-    TERM: {
-        type: 2,
-        name: '领取之后可用'
-    }
-}
+  DATE: {
+    type: 1,
+    name: '固定日期可用',
+  },
+  TERM: {
+    type: 2,
+    name: '领取之后可用',
+  },
+};
 
 /**
  * 营销的商品范围枚举
  */
 export const PromotionProductScopeEnum = {
-    ALL: {
-        scope: 1,
-        name: '通用劵'
-    },
-    SPU: {
-        scope: 2,
-        name: '商品劵'
-    },
-    CATEGORY: {
-        scope: 3,
-        name: '品类劵'
-    }
-}
+  ALL: {
+    scope: 1,
+    name: '通用劵',
+  },
+  SPU: {
+    scope: 2,
+    name: '商品劵',
+  },
+  CATEGORY: {
+    scope: 3,
+    name: '品类劵',
+  },
+};
 
 
 // 时间段的状态枚举
 export const TimeStatusEnum = {
-    WAIT_START: '即将开始',
-    STARTED: '进行中',
-    END: '已结束',
-}
+  WAIT_START: '即将开始',
+  STARTED: '进行中',
+  END: '已结束',
+};
 
 /**
  * 微信小程序的订阅模版
  */
 export const WxaSubscribeTemplate = {
-  TRADE_ORDER_DELIVERY: "订单发货通知",
-  PROMOTION_COMBINATION_SUCCESS: "拼团结果通知",
-  PAY_WALLET_RECHARGER_SUCCESS: "充值成功通知",
-}
+  TRADE_ORDER_DELIVERY: '订单发货通知',
+  PROMOTION_COMBINATION_SUCCESS: '拼团结果通知',
+  PAY_WALLET_RECHARGER_SUCCESS: '充值成功通知',
+};
+export const PromotionActivityTypeEnum = {
+  NORMAL: {
+    type: 0,
+    name: '普通',
+  },
+  SECKILL: {
+    type: 1,
+    name: '秒杀',
+  },
+  BARGAIN: {
+    type: 2,
+    name: '砍价',
+  },
+  COMBINATION: {
+    type: 3,
+    name: '拼团',
+  },
+  POINT: {
+    type: 4,
+    name: '积分商城',
+  },
+};
 
 export const getTimeStatusEnum = (startTime, endTime) => {
-    const now = dayjs();
-    if (now.isBefore(startTime)) {
-        return TimeStatusEnum.WAIT_START;
-    } else if (now.isAfter(endTime)) {
-        return TimeStatusEnum.END;
-    } else {
-        return TimeStatusEnum.STARTED;
-    }
-}
+  const now = dayjs();
+  if (now.isBefore(startTime)) {
+    return TimeStatusEnum.WAIT_START;
+  } else if (now.isAfter(endTime)) {
+    return TimeStatusEnum.END;
+  } else {
+    return TimeStatusEnum.STARTED;
+  }
+};