feat:共富结算页面

This commit is contained in:
ctw committed 2025-10-29 19:50:08 +08:00
1 parent 8f5e1d0641
commit 763522c8d6
9 files changed
+190 -93

No files matched your search

+2 -2
View File
@@ -200,9 +200,9 @@
}
},
{
"path": "goods-cart",
"path": "settlement",
"style": {
"navigationBarTitleText": "购物车",
"navigationBarTitleText": "结算",
"disableScroll": true
}
}
@@ -1,6 +1,5 @@
<template>
<crud-layout title="购物车" mainIsScroll bg="/static/page/blue-bg.png">
<view class="h-20rpx"></view>
<tm-drawer z-index="800" v-model:show="modelValue" showClose title="购物车" size="80%" bgColor="#ECF4F9" @close="doClose">
<view v-if="totPrice > 0" class="flex-row card px-15rpx py-25rpx mb-20rpx" v-for="(v, i) in cartList" :key="i">
<image class="size-160rpx rounded-12rpx mr-20rpx bg-#eeeeee" :src="filePath(v.productPic)" mode="aspectFill" />
<view class="flex-1 overflow-hidden">
@@ -15,12 +14,12 @@
<view class="flex-row justify-between items-center">
<view
class="flex-row-center size-40rpx rounded-full border-1px border-solid border-color-#0094ff"
@tap.stop="removeProductCount(v.productId)"
@tap.stop="removeProductCount(v.productId, merchantId)"
>
<view class="iconfont icon-a--" />
</view>
<view class="sub-text-28 m-x-20rpx">{{ v.productCount }}</view>
<view class="flex-row-center size-40rpx rounded-full bg-#0094ff" @tap.stop="addProductCount(v.productId)">
<view class="flex-row-center size-40rpx rounded-full bg-#0094ff" @tap.stop="addProductCount(v.productId, merchantId)">
<view class="font-size-40rpx color-white iconfont icon-a-" />
</view>
</view>
@@ -33,26 +32,26 @@
<text class="sub-text-32 font-bold">购物车空空如也</text>
</view>
<template #main-bottom>
<view class="z-200 p-x-30rpx p-y-30rpx bg-white">
<product-total :totPrice="totPrice" :totCount="totalCount" @doContainer="" @submit="doBuy" />
</view>
</template>
</crud-layout>
<view class="h-100rpx"></view>
</tm-drawer>
</template>
<script setup lang="ts">
import { onLoad } from "@dcloudio/uni-app"
import { hooks } from "@/sheep"
import { filePath } from "@/sheep/utils/file"
import ProductTotal from "./components/product-total.vue"
import useCartBuy from "./use-cart-buy"
import useCartBuy from "../use-cart-buy"
import { hooks } from "@/sheep"
const { totPrice, totalCount, cartList, getShopCart, addProductCount, removeProductCount, doBuy } = useCartBuy()
onLoad(async (option: any) => {
const { merchantId } = option
if (!merchantId) return uni.showToast({ title: "参数错误", icon: "error" })
await getShopCart(merchantId)
const modelValue = defineModel("modelValue", { default: false })
const props = defineProps({
merchantId: {
type: String,
default: null,
},
})
const { totPrice, cartList, addProductCount, removeProductCount } = useCartBuy()
// 关闭
const doClose = () => {
modelValue.value = false
}
</script>
@@ -1,5 +1,5 @@
<template>
<tm-drawer z-index="800" v-model:show="modelValue" showFooter showClose title="加入购物车" size="70%" bgColor="#ECF4F9" @close="doClose">
<tm-drawer z-index="2000" v-model:show="modelValue" showFooter showClose title="加入购物车" size="70%" bgColor="#ECF4F9" @close="doClose">
<view class="flex-col card py-20rpx px-30rpx mb-20rpx">
<view class="prefix_title mb-15rpx">商品信息</view>
<view class="flex items-center">
@@ -28,9 +28,9 @@
</view>
</view>
<!-- 包装单位 -->
<!-- 规格 -->
<view class="flex-col card p-y-20rpx p-x-30rpx mb-20rpx">
<view class="prefix_title mb-15rpx">包装单位</view>
<view class="prefix_title mb-15rpx">规格</view>
<view class="flex flex-wrap">
<view
class="text-center rounded-2 mr-4 mb-2 py-2 px-3 text-28 bg-#F2F2F2 c-black border border-solid border-#E5E5E5"
@@ -1,18 +1,21 @@
<template>
<view class="flex-row items-center justify-between" @tap="doContainer">
<view class="flex-row-center">
<image class="size-100rpx" src="/static/icon/cart.png" />
<tm-badge bg-color="red" :label="totalCount" :offset="[8, 8]">
<image class="size-100rpx" src="/static/icon/cart.png" />
</tm-badge>
<view class="flex-col m-l-30rpx">
<view class="second-text-36 color-#f63a36!">¥ {{ hooks.useMoney(props.totPrice) }}</view>
<view class="sub-text-28">共{{ props.totCount }}件</view>
</view>
</view>
<view class="bg-#0094ff p-x-30rpx p-y-20rpx text-center rounded-40rpx sub-text-30 color-white!" @tap.stop="doBuy">提交订单</view>
<view class="bg-#0094ff p-x-60rpx p-y-20rpx text-center rounded-40rpx sub-text-30 color-white!" @tap.stop="goSettlement">去结算</view>
</view>
</template>
<script setup lang="ts">
import { hooks } from "@@/index"
import useCartBuy from "../use-cart-buy"
const emit = defineEmits(["submit", "doContainer"])
@@ -27,7 +30,9 @@ const props = withDefaults(
},
)
const doBuy = () => emit("submit")
const { totalCount } = useCartBuy()
const goSettlement = () => emit("submit")
const doContainer = () => emit("doContainer")
</script>
+46 -46
View File
@@ -1,41 +1,45 @@
<template>
<crud-layout mainIsScroll bg="/static/page/blue-bg.png">
<image :src="filePath(state.detail.coverImage)" class="w-full h-500rpx bg-#eeeeee" mode="aspectFill" />
<view v-if="state.detail.id" class="card p-20rpx mt-10rpx mx-20rpx bg-gradient-to-b from-#0094ff33 to-#fff">
<view v-if="state.detail.priceType == '2'" class="w-full flex justify-between items-center">
<image :src="filePath(goodsDetail.coverImage)" class="w-full h-500rpx bg-#eeeeee" mode="aspectFill" />
<view v-if="goodsDetail.id" class="card p-20rpx mt-10rpx mx-20rpx bg-gradient-to-b from-#0094ff33 to-#fff">
<view v-if="goodsDetail.priceType == '2'" class="w-full flex justify-between items-center">
<view class="flex items-center">
<text class="second-text-34 line-through">¥</text>
<text class="font-bold second-text-40 line-through mr-2">{{ displayPrice(state.detail.originalPrice, "") }}</text>
<text class="font-bold second-text-40 line-through mr-2">{{ displayPrice(goodsDetail.originalPrice, "") }}</text>
<text class="text-34rpx color-red!">¥</text>
<text class="text-46rpx font-bold color-red!">{{ displayPrice(state.detail.spuPrice, "") }}</text>
<text class="text-46rpx font-bold color-red!">{{ displayPrice(goodsDetail.spuPrice, "") }}</text>
<text class="view-clip px-2 text-22rpx c-white bg-red ml-2 rounded-r-1 rounded-lt-1">到手价</text>
</view>
<view class="main-text-32 c-red! font-italic">
<text>约省</text>
<text class="text-44rpx mx-1">{{ displayPrice(Number(state.detail.originalPrice) - Number(state.detail.spuPrice), "") }}</text>
<text class="text-44rpx mx-1">{{ displayPrice(Number(goodsDetail.originalPrice) - Number(goodsDetail.spuPrice), "") }}</text>
<text>元</text>
</view>
</view>
<view v-else class="w-full flex justify-start items-center">
<text class="text-34rpx color-red!">¥</text>
<text class="text-46rpx font-bold color-red!">{{ displayPrice(state.detail.skuList[0].price, "") }}</text>
<text class="text-46rpx font-bold color-red!">{{ displayPrice(goodsDetail.skuList[0].price, "") }}</text>
<text class="view-clip px-2 text-22rpx c-white bg-red ml-2 rounded-r-1 rounded-lt-1">到手价</text>
</view>
<view class="w-full sub-text-36 flex items-center mt-1">
<text class="c-#0094ff! sub-text-24 px-2 bg-#0094ff22 rounded-1 mr-2 whitespace-nowrap">
{{ state.detail.status == "0" ? "在售" : "未售" }}
{{ goodsDetail.status == "0" ? "在售" : "未售" }}
</text>
<text class="truncate">{{ state.detail.title }}</text>
<text class="truncate">{{ goodsDetail.title }}</text>
</view>
<view class="second-text-26 mt-1">售卖时间 {{ state.detail.saleStartTime }} ~ {{ state.detail.saleEndTime }}</view>
<view class="second-text-26 truncate mt-1">
<text class="mr-20rpx">售卖单位 {{ state.detail.unit }}</text>
<text class="mr-20rpx">剩余库存 {{ state.detail.totalStock }}</text>
<view class="second-text-26 mt-1">售卖时间 {{ goodsDetail.saleStartTime }} ~ {{ goodsDetail.saleEndTime }}</view>
<view class="second-text-26 truncate mt-1 flex justify-between items-center">
<view>
<text class="mr-20rpx">售卖单位 {{ goodsDetail.unit }}</text>
<text class="mr-20rpx">剩余库存 {{ goodsDetail.totalStock }}</text>
</view>
<view class="second-text-24 px-2 py-8rpx bg-#0094ff c-white! border-rd-8" @tap.stop="state.showSkuDialog = true">加入购物车</view>
</view>
</view>
<view v-if="state.detail.priceType == '1'" class="mt-20rpx card p-20rpx mx-20rpx">
<view class="prefix_title">包装单位</view>
<view class="bg-#1879ff09 rounded-1 my-2 p-3" v-for="(item, index) in state.detail.skuList" :key="index">
<view v-if="goodsDetail.priceType == '1'" class="mt-20rpx card p-20rpx mx-20rpx">
<view class="prefix_title">规格</view>
<view class="bg-#1879ff09 rounded-1 my-2 p-3" v-for="(item, index) in goodsDetail.skuList" :key="index">
<view class="sub-text-30">{{ item.skuName }}</view>
<view class="second-text-28 mt-1 flex justify-between items-center">
<text>售价 {{ displayPrice(item.price) }}</text>
@@ -44,76 +48,72 @@
</view>
</view>
</view>
<view class="mt-20rpx card p-20rpx mx-20rpx">
<view class="prefix_title">商品描述</view>
<view class="mt-20rpx overflow-auto text-26rpx!" v-html="state.detail.description"></view>
<view class="mt-20rpx overflow-auto text-26rpx!" v-html="goodsDetail.description"></view>
</view>
<view class="h-30rpx" />
<template #main-bottom>
<view class="flex-row justify-between items-center my-4 mx-12">
<tm-badge bg-color="red" :label="cartStore.totalCount">
<view class="flex-col-center" @tap="goCart">
<image class="size-60rpx" src="/static/icon/cart.png" />
<view class="c-#0094ff text-20rpx">购物车</view>
</view>
</tm-badge>
<view class="flex-1 ml-8 rounded-3 text-center bg-#0094ff py-2 c-white" @tap="state.showSkuDialog = true">加入购物车</view>
<view class="z-200 p-x-30rpx p-y-30rpx bg-white">
<product-total :totPrice="totPrice" :totCount="totalCount" @doContainer="doCart" @submit="goSettlement" />
</view>
</template>
</crud-layout>
<product-sku v-model="state.showSkuDialog" :goodsInfo="state.detail" @onSkuAddToCart="onSkuAddToCart" />
<product-sku v-model="state.showSkuDialog" :goodsInfo="state.goodsDetail" @onSkuAddToCart="onSkuAddToCart" />
<product-cart v-model="state.showCartDialog" :merchantId="state.mchId" />
</template>
<script setup lang="ts">
import { onLoad } from "@dcloudio/uni-app"
import { reactive } from "vue"
import { computed, reactive } from "vue"
import { prosperityShopApi } from "@/sheep/api"
import { filePath } from "@/sheep/utils/file"
import { displayPrice } from "@/sheep/utils/formatMoney"
import ProductTotal from "./components/product-total.vue"
import ProductSku from "./components/product-sku.vue"
import { hooks, router } from "@/sheep"
import { useProsperityCartStore } from "@/sheep/stores/prosperity-cart"
import ProductCart from "./components/product-cart.vue"
import useCartBuy from "./use-cart-buy"
const cartStore = useProsperityCartStore()
const { totPrice, totalCount, skuAddToCart, getShopCart, goSettlement } = useCartBuy()
const state = reactive<any>({
id: "",
merchantId: "",
detail: {},
mchId: "",
goodsDetail: {},
showSkuDialog: false,
showCartDialog: false,
})
const goodsDetail = computed(() => state.goodsDetail)
onLoad(async (option: any) => {
const { id, merchantId } = option
if (!id || !merchantId) return uni.showToast({ title: "参数错误", icon: "error" })
const { id, mchId } = option
if (!id || !mchId) return uni.showToast({ title: "参数错误", icon: "error" })
state.id = option.id
state.merchantId = option.merchantId
state.mchId = option.mchId
uni.showLoading({ title: "加载中..." })
await getGoodsDetail(id)
await cartStore.getShopCart(merchantId)
await getShopCart(mchId)
uni.hideLoading()
})
// 获取商品详情
const getGoodsDetail = async (id: string) => {
const { code, data, msg } = await prosperityShopApi.getGoodsDetail(id)
if (code != 0) return uni.showToast({ title: msg || "商品详情获取失败", icon: "none" })
state.detail = data
state.goodsDetail = data
}
// 选择sku确认加入到购物车
// 选择sku加入到购物车
const onSkuAddToCart = (sku: any) => {
cartStore.addGoodsItemToCart({ ...state.detail, ...sku, productId: sku.skuId })
cartStore.updateShopCart(state.merchantId)
skuAddToCart({ ...state.goodsDetail, ...sku, productId: sku.skuId }, state.mchId)
state.showSkuDialog = false
}
const goCart = async () => {
const isLogin = await hooks.useCheckLogin()
if (isLogin)
router.jump("/pages/prosperity-shop/goods-cart", {
merchantId: state.merchantId,
})
// 查看购物车
const doCart = () => {
state.showCartDialog = true
}
</script>
+66
View File
@@ -0,0 +1,66 @@
<template>
<crud-layout title="结算" mainIsScroll bg="/static/page/blue-bg.png">
<view class="h-20rpx" />
<view class="bg-#FFA61Ecc color-#fff px-2 py-1 text-28rpx rounded-2">温馨提示:当天的订单预计明天开始配送</view>
<tm-sticky-header>
<view class="h-20rpx" />
<view class="card p-20rpx">
<view class="text-36rpx">请选择自提点</view>
<!-- <tm-picker rang-key="title" rang-text="title" v-model="state.curPickUp" v-model:model-str="state.curPickUp" :list="state.pickUpList"> -->
<view class="flex-row items-center justify-between">
<view class="sub-text-28">请选择自提点</view>
<view class="flex-row items-center second-text-24">
<text>{{ 0 || "请选择自提点" }} </text>
<text class="ml-10rpx color-#b1b1b1 iconfont icon-xiangxiajiantouxiao" />
</view>
</view>
<!-- </tm-picker> -->
<view class="c-#0089ff text-24rpx">配送订单较多时,配送时间可能波动</view>
</view>
<view class="h-20rpx" />
</tm-sticky-header>
<view class="card p-20rpx mb-20rpx mx-1">
<view v-if="totalCount > 0" class="flex-row px-15rpx mb-20rpx" v-for="(v, i) in cartList" :key="i">
<image class="size-125rpx rounded-12rpx mr-20rpx bg-#eeeeee" :src="filePath(v.productPic)" mode="aspectFill" />
<view class="flex-1 overflow-hidden">
<view class="sub-text-30 truncate">{{ v.productName }}</view>
<view class="flex justify-between items-center">
<view class="flex-col">
<view class="second-text-30">¥{{ hooks.useMoney(v.productPrice) }}</view>
<view class="second-text-30">x {{ v.productCount }}</view>
</view>
<view class="second-text-32 c-red!">¥{{ hooks.useMoney(v.totalPrice) }}</view>
</view>
</view>
</view>
<view v-else class="text-center second-text-28">你尚未选择任何商品</view>
</view>
<view class="h-20rpx" />
<template #main-bottom>
<view class="flex justify-end items-center p-4">
<view class="flex-col mr-4">
<view class="second-text-36 color-#f63a36!">¥ {{ hooks.useMoney(totPrice) }}</view>
<view class="sub-text-28">共{{ totalCount }}件</view>
</view>
<view class="bg-#0094ff px-60rpx py-20rpx text-center rounded-full sub-text-32 color-white!" @tap.stop="doBuy">提交订单</view>
</view>
</template>
</crud-layout>
</template>
<script setup lang="ts">
import { reactive } from "vue"
import { hooks } from "@/sheep"
import useCartBuy from "./use-cart-buy"
import { filePath } from "@/sheep/utils/file"
const { cartList, totPrice, totalCount, doBuy } = useCartBuy()
const state = reactive({
pickUpList: [],
curPickUp: {},
})
</script>
+14 -5
View File
@@ -43,7 +43,7 @@
style="height: calc(100vh - 420rpx)"
>
<view v-for="v in state.goodsList" :key="v.id" class="card flex mx-15rpx mb-2 p-2" @click="doGoodsDetail(v.id)">
<image :src="filePath(v.coverImage)" class="size-160rpx rounded-12rpx bg-#eeeeee" mode="aspectFill" />
<image :src="filePath(v.coverImage)" class="size-170rpx rounded-12rpx bg-#eeeeee" mode="aspectFill" />
<view class="flex-1 ml-2 overflow-hidden">
<view class="truncate sub-text-30">{{ v.title }}</view>
<view>
@@ -85,17 +85,18 @@
<template #main-bottom>
<view class="z-200 p-x-30rpx p-y-30rpx bg-white">
<product-total :totPrice="totPrice" :totCount="totalCount" @doContainer="" @submit="doBuy" />
<product-total :totPrice="totPrice" :totCount="totalCount" @doContainer="doCart" @submit="goSettlement" />
</view>
</template>
</crud-layout>
<product-sku v-model="state.showSkuDialog" :goodsInfo="state.goodsDetail" @onSkuAddToCart="onSkuAddToCart" />
<product-cart v-model="state.showCartDialog" :merchantId="state.mchId" />
</template>
<script setup lang="ts">
import { computed, reactive } from "vue"
import { prosperityShopApi } from "@/sheep/api"
import { onLoad } from "@dcloudio/uni-app"
import { prosperityShopApi } from "@/sheep/api"
import { filePath } from "@/sheep/utils/file"
import treeToList from "@/sheep/utils/tree-to-list"
import { displayPrice } from "@/sheep/utils/formatMoney"
@@ -103,6 +104,7 @@ import useShopDetailScroll from "./use-shop-detail-scroll"
import useCartBuy from "./use-cart-buy"
import ProductTotal from "./components/product-total.vue"
import ProductSku from "./components/product-sku.vue"
import ProductCart from "./components/product-cart.vue"
const state = reactive<any>({
mchId: "",
@@ -112,11 +114,12 @@ const state = reactive<any>({
goodsList: [],
goodsDetail: {},
showSkuDialog: false,
showCartDialog: false,
})
const mchDetail = computed(() => state.mchDetail)
const { scrollDetail, onScroll, filterStyle, searchStyle } = useShopDetailScroll()
const { totPrice, totalCount, skuAddToCart, doBuy } = useCartBuy()
const { totPrice, totalCount, skuAddToCart, getShopCart, goSettlement } = useCartBuy()
onLoad(async (option: any) => {
const { id } = option
@@ -126,6 +129,7 @@ onLoad(async (option: any) => {
await getMchDetail(id)
await getGoodsCategoryTree(id)
await getGoodsList()
await getShopCart(id)
uni.hideLoading()
})
@@ -169,7 +173,7 @@ const doCategory = async (index: number) => {
const doGoodsDetail = (id: string) => {
if (!id || !state.mchId) return uni.showToast({ title: "id错误", icon: "none" })
uni.navigateTo({
url: `/pages/prosperity-shop/goods-detail?id=${id}&merchantId=${state.mchId}`,
url: `/pages/prosperity-shop/goods-detail?id=${id}&mchId=${state.mchId}`,
})
}
@@ -195,6 +199,11 @@ const onSkuAddToCart = (sku: any) => {
skuAddToCart({ ...state.goodsDetail, ...sku, productId: sku.skuId }, state.mchId)
state.showSkuDialog = false
}
// 查看购物车
const doCart = () => {
state.showCartDialog = true
}
</script>
<style lang="scss" scoped>
+26 -8
View File
@@ -2,16 +2,25 @@ import { router } from "@/sheep"
import { orderApi } from "@/sheep/api"
import { useProsperityCartStore } from "@/sheep/stores/prosperity-cart"
import { isEmpty } from "radash"
import { computed } from "vue"
export default function useCartBuy() {
const cartStore = useProsperityCartStore()
// 购物车商品总金额
const totPrice = cartStore.totPrice
const totPrice = computed(() => {
return cartStore.totPrice
})
// 购物车商品总数量
const totalCount = cartStore.totalCount
const totalCount = computed(() => {
return cartStore.totalCount
})
// 购物车商品列表
const cartList = cartStore.cartList
const cartList = computed(() => {
return cartStore.cartList
})
// 选择sku确认加入到购物车
const skuAddToCart = (sku: any, merchantId: string) => {
@@ -23,18 +32,26 @@ export default function useCartBuy() {
const getShopCart = async (merchantId: string) => {
await cartStore.getShopCart(merchantId)
}
// 添加一个商品数量
const addProductCount = async (productId: string) => {
await cartStore.addProductCount(productId)
const addProductCount = async (productId: string, merchantId: string) => {
if (!merchantId) return
await cartStore.addProductCount(productId, merchantId)
}
// 减少一个商品数量
const removeProductCount = async (productId: string) => {
await cartStore.removeProductCount(productId)
const removeProductCount = async (productId: string, merchantId: string) => {
if (!merchantId) return
await cartStore.removeProductCount(productId, merchantId)
}
const goSettlement = () => {
uni.navigateTo({ url: "/pages/prosperity-shop/settlement" })
}
// 点击提交订单
const doBuy = async () => {
if (isEmpty(cartStore.cartList)) return uni.showToast({ title: "请至少购买一件商品", icon: "none" })
if (isEmpty(cartList.value)) return uni.showToast({ title: "请至少购买一件商品", icon: "none" })
uni.showModal({
title: "提示",
content: "是否确定购买",
@@ -72,6 +89,7 @@ export default function useCartBuy() {
skuAddToCart,
addProductCount,
removeProductCount,
goSettlement,
doBuy,
}
}
+6 -6
View File
@@ -32,24 +32,24 @@ export const useProsperityCartStore = defineStore("prosperityCartStore", {
}
},
// 购物车商品项数量减一
async removeProductCount(productId: string) {
async removeProductCount(productId: string, merchantId: string) {
this.cartList.forEach((item: any) => {
if (item.productId === productId) {
item.productCount--
}
})
await this.updateShopCart()
await this.getShopCart()
await this.updateShopCart(merchantId)
await this.getShopCart(merchantId)
},
// 购物车商品项数量加一
async addProductCount(productId: string) {
async addProductCount(productId: string, merchantId: string) {
this.cartList.forEach((item: any) => {
if (item.productId === productId) {
item.productCount++
}
})
await this.updateShopCart()
await this.getShopCart()
await this.updateShopCart(merchantId)
await this.getShopCart(merchantId)
},
// 获取购物车商品列表
async getShopCart(merchantId: string) {