feat:在线商城
This commit is contained in:
1 parent
bc24d80a33
commit
391bf62d9c
14 files changed
+165
-353
No files matched your search
+10
-5
@@ -118,18 +118,23 @@
|
||||
"navigationBarTitleText": "",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/online-shop",
|
||||
"pages": [
|
||||
{
|
||||
"path": "product-detail",
|
||||
"path": "cart",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarTitleText": "购物车",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "cart",
|
||||
"path": "goods-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarTitleText": "商品详情",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
|
||||
File renamed without changes.
File renamed without changes.
+1
-1
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<view
|
||||
class="flex-row items-start card p-x-15rpx p-y-25rpx m-b-20rpx"
|
||||
@tap="props.productId && props.mode == 'default' && router.jump('/pages/shop/product-detail', { id: props.productId })"
|
||||
@tap="props.productId && props.mode == 'default' && router.jump('/pages/online-shop/goods-detail', { id: props.productId })"
|
||||
>
|
||||
<image class="size-160rpx rounded-12rpx" :src="props.picUrl" mode="aspectFill" />
|
||||
<view class="flex-1 m-l-20rpx">
|
||||
+51
-54
@@ -11,66 +11,61 @@
|
||||
:duration="100"
|
||||
@close="doClose"
|
||||
>
|
||||
<scroll-view scroll-y="true" @touchmove.stop>
|
||||
<!-- 商品信息 -->
|
||||
<view class="flex-col card p-y-20rpx p-x-30rpx mb-20rpx">
|
||||
<view class="prefix_title mb-15rpx">商品信息</view>
|
||||
<view class="flex-row items-center">
|
||||
<image
|
||||
class="w-160rpx h-160rpx bg-#0094ff rounded-1"
|
||||
:src="filePath(state.goodsDetail.picUrl)"
|
||||
mode="aspectFill"
|
||||
@tap.stop="state.goodsDetail.picUrl && usePreviewImage(filePath(state.goodsDetail.picUrl))"
|
||||
/>
|
||||
<view class="ml-3 flex flex-col justify-between">
|
||||
<view class="text-32 ws-nowrap text-ellipsis overflow-hidden">{{ state.goodsDetail.productName }}</view>
|
||||
<view class="flex items-center">
|
||||
<view class="second-text-30 c-red!">
|
||||
促销 ¥ {{ state.selectedSku.promotionPrice.toFixed(2) || state.selectedSku.retailPrice.toFixed(2) || 0 }}
|
||||
</view>
|
||||
<view class="m-l-20rpx second-text-28 line-through">原价 ¥ {{ state.selectedSku.retailPrice.toFixed(2) || 0 }}</view>
|
||||
</view>
|
||||
<view class="second-text-26">库存:{{ state.selectedSku.stock || 0 }}</view>
|
||||
<view class="second-text-26">
|
||||
已选择:{{ `${state.selectedSku.spec || "未选择"} / ${state.selectedSku.unit || "未选择"},数量:${state.goodsCount}` }}
|
||||
</view>
|
||||
<view class="flex-col card py-20rpx px-30rpx mb-20rpx">
|
||||
<view class="prefix_title mb-15rpx">商品信息</view>
|
||||
<view class="flex items-center">
|
||||
<image
|
||||
class="size-160rpx bg-#eeeeee rounded-1 mr-2"
|
||||
:src="filePath(state.goodsDetail.picUrl)"
|
||||
mode="aspectFill"
|
||||
@tap.stop="state.goodsDetail.picUrl && usePreviewImage(filePath(state.goodsDetail.picUrl))"
|
||||
/>
|
||||
<view class="flex-1 overflow-hidden">
|
||||
<view class="sub-text-32 truncate">{{ state.goodsDetail.productName }}</view>
|
||||
<view class="second-text-32 c-red!">
|
||||
<text> ¥{{ displayPrice(state.selectedSku.promotionPrice, "") || displayPrice(state.selectedSku.retailPrice, "") || 0 }} </text>
|
||||
<text class="m-l-20rpx second-text-28 line-through">¥{{ displayPrice(state.selectedSku.retailPrice, "") || 0 }}</text>
|
||||
</view>
|
||||
<view class="second-text-26">库存 {{ state.selectedSku.stock || 0 }}</view>
|
||||
<view class="second-text-26">
|
||||
已选择 {{ `${state.selectedSku.spec || "未选择"} / ${state.selectedSku.unit || "未选择"},数量 ${state.goodsCount}` }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 包装单位 -->
|
||||
<view class="flex-col card p-y-20rpx p-x-30rpx mb-20rpx">
|
||||
<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"
|
||||
:class="{ 'bg-#0094ff! c-white!': state.selectedSku.id === v.id }"
|
||||
v-for="v in state.goodsDetail?.skuList"
|
||||
:key="v.id"
|
||||
@click="onSelectSku(v)"
|
||||
>
|
||||
{{ v.spec + " / " + v.unit }}
|
||||
</view>
|
||||
<!-- 包装单位 -->
|
||||
<view class="flex-col card p-y-20rpx p-x-30rpx mb-20rpx">
|
||||
<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"
|
||||
:class="{ 'bg-#0094ff! c-white!': state.selectedSku.id === v.id }"
|
||||
v-for="v in state.goodsDetail?.skuList"
|
||||
:key="v.id"
|
||||
@click="onSelectSku(v)"
|
||||
>
|
||||
{{ v.spec + " / " + v.unit }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 购买数量 -->
|
||||
<view class="flex-col card p-y-20rpx p-x-30rpx mb-20rpx">
|
||||
<view class="prefix_title mb-15rpx">购买数量</view>
|
||||
<view class="flex items-center justify-between">
|
||||
<view class="second-text-28">限购:{{ state.goodsDetail.limitNum }}</view>
|
||||
<view class="flex">
|
||||
<view class="flex-row-center size-40rpx rounded-full border-1px border-solid border-color-#0094ff" @tap.stop="handleNumRemove">
|
||||
<view class="iconfont icon-a--" />
|
||||
</view>
|
||||
<view class="sub-text-28 m-x-20rpx">{{ String(state.goodsCount).padStart(2, "0") }}</view>
|
||||
<view class="flex-row-center size-40rpx rounded-full bg-#0094ff" @tap.stop="handleNumAdd">
|
||||
<view class="font-size-40rpx color-white iconfont icon-a-" />
|
||||
</view>
|
||||
<!-- 购买数量 -->
|
||||
<view class="flex-col card p-y-20rpx p-x-30rpx mb-20rpx">
|
||||
<view class="prefix_title mb-15rpx">购买数量</view>
|
||||
<view class="flex items-center justify-between">
|
||||
<view class="second-text-28">限购 {{ state.goodsDetail.limitNum }}</view>
|
||||
<view class="flex">
|
||||
<view class="flex-row-center size-40rpx rounded-full border-1px border-solid border-color-#0094ff" @tap.stop="handleNumRemove">
|
||||
<view class="iconfont icon-a--" />
|
||||
</view>
|
||||
<view class="sub-text-28 m-x-20rpx">{{ String(state.goodsCount).padStart(2, "0") }}</view>
|
||||
<view class="flex-row-center size-40rpx rounded-full bg-#0094ff" @tap.stop="handleNumAdd">
|
||||
<view class="font-size-40rpx color-white iconfont icon-a-" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<template #footer>
|
||||
<button
|
||||
@@ -89,17 +84,18 @@ import { filePath } from "@/sheep/utils/file"
|
||||
import { reactive, watch } from "vue"
|
||||
import { usePreviewImage } from "@/sheep/hooks/use-img"
|
||||
import { isEmpty } from "radash"
|
||||
import { displayPrice } from "@/sheep/utils/formatMoney"
|
||||
|
||||
const emit = defineEmits(["update:modelValue", "onSkuAddToCart"])
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
modelValue: boolean
|
||||
productData: any
|
||||
goodsData: any
|
||||
}>(),
|
||||
{
|
||||
modelValue: false,
|
||||
productData: {},
|
||||
goodsData: {},
|
||||
},
|
||||
)
|
||||
|
||||
@@ -117,7 +113,7 @@ watch(
|
||||
() => props.modelValue,
|
||||
async (newValue) => {
|
||||
if (newValue) {
|
||||
state.goodsDetail = props.productData
|
||||
state.goodsDetail = props.goodsData
|
||||
if (!isEmpty(state.goodsDetail)) {
|
||||
state.selectedSku = state.goodsDetail.skuList[0]
|
||||
}
|
||||
@@ -140,6 +136,7 @@ const handleNumAdd = () => {
|
||||
if (state.goodsCount >= state.goodsDetail.stock) return uni.showToast({ title: "库存不足", icon: "none" })
|
||||
state.goodsCount += 1
|
||||
}
|
||||
|
||||
// 减数量
|
||||
const handleNumRemove = () => {
|
||||
if (state.goodsCount <= 1) return
|
||||
@@ -148,7 +145,6 @@ const handleNumRemove = () => {
|
||||
|
||||
// 点击sku加入到购物车
|
||||
const handleSkuAddToCart = async () => {
|
||||
// 检查包装单位选择
|
||||
if (!state.selectedSku.id) return uni.showToast({ title: "请选择包装单位", icon: "none" })
|
||||
|
||||
// 检查库存
|
||||
@@ -161,6 +157,7 @@ const handleSkuAddToCart = async () => {
|
||||
// } finally {
|
||||
// uni.hideLoading()
|
||||
// }
|
||||
|
||||
// 检查库存
|
||||
if (state.goodsDetail.stock === 0 || Number(state.goodsCount) > Number(state.selectedSku.stock))
|
||||
return uni.showToast({ title: "库存不足", icon: "none" })
|
||||
File renamed without changes.
@@ -1,7 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive } from "vue"
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app"
|
||||
import { isEmpty } from "radash"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { onlineShopApi } from "@@/api"
|
||||
import { filePath } from "@/sheep/utils/file"
|
||||
import ProductSku from "./components/product-sku.vue"
|
||||
@@ -17,41 +16,38 @@ const state = reactive<any>({
|
||||
})
|
||||
|
||||
onLoad((options: any) => {
|
||||
if (!isEmpty(options.id)) {
|
||||
state.detailId = options.id
|
||||
}
|
||||
})
|
||||
onShow(() => {
|
||||
getDetail()
|
||||
const { id } = options
|
||||
if (!id) return uni.showToast({ title: "参数错误" })
|
||||
state.detailId = id
|
||||
getGoodsDetail()
|
||||
})
|
||||
|
||||
const getDetail = async () => {
|
||||
// 获取商品详情
|
||||
const getGoodsDetail = async () => {
|
||||
const { data } = await onlineShopApi.getSpuDetail(state.detailId)
|
||||
state.detail = data ?? {}
|
||||
}
|
||||
|
||||
// 加入购物车
|
||||
// 打开加入购物车
|
||||
const addToCart = () => {
|
||||
state.showSkuDialog = true
|
||||
}
|
||||
|
||||
// 选择sku加入到购物车
|
||||
// 选择sku确认加入到购物车
|
||||
const onSkuAddToCart = (sku: any) => {
|
||||
cartStore.addGoodsItemToCart({ ...state.detail, ...sku, productId: sku.skuId })
|
||||
cartStore.updateShopCart()
|
||||
state.showSkuDialog = false
|
||||
}
|
||||
|
||||
const doCart = async () => {
|
||||
const goCart = async () => {
|
||||
const isLogin = await hooks.useCheckLogin()
|
||||
if (isLogin) {
|
||||
router.jump("/pages/shop/cart")
|
||||
}
|
||||
if (isLogin) router.jump("/pages/online-shop/cart")
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<crud-layout title="订单详情" mainIsScroll tabBarType="just-flot-back" bg="/static/page/blue-bg.png">
|
||||
<crud-layout title="订单详情" mainIsScroll bg="/static/page/blue-bg.png">
|
||||
<swiper
|
||||
class="w-100vw h-30vh"
|
||||
circular
|
||||
@@ -66,53 +62,43 @@ const doCart = async () => {
|
||||
</swiper>
|
||||
|
||||
<view class="p-15rpx">
|
||||
<view class="flex-col justify-between card p-y-20rpx p-x-30rpx">
|
||||
<view class="prefix_title mb-15rpx">商品</view>
|
||||
<view class="px-3">{{ state.detail?.productName }}</view>
|
||||
<view class="flex-row items-center justify-between m-t-15rpx px-3">
|
||||
<view class="second-text-26">限购:{{ state.detail?.limitNum || 0 }}</view>
|
||||
<view class="second-text-26">已售:{{ state.detail?.salesCount || 0 }}</view>
|
||||
<view class="flex-col justify-between card py-20rpx px-30rpx mb-2">
|
||||
<view class="prefix_title mb-15rpx">商品信息</view>
|
||||
<view class="px-3 sub-text-32 truncate w-full">{{ state.detail?.productName }}</view>
|
||||
<view class="flex-row items-center justify-end mt-15rpx px-3 gap-4 second-text-26">
|
||||
<view>限购 {{ state.detail?.limitNum || 0 }}</view>
|
||||
<view>已售 {{ state.detail?.salesCount || 0 }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="h-15rpx" />
|
||||
<view class="flex-col justify-between card p-y-20rpx p-x-30rpx">
|
||||
<view class="prefix_title mb-15rpx">包装</view>
|
||||
<view class="flex-col justify-between card py-20rpx px-30rpx mb-2">
|
||||
<view class="prefix_title mb-15rpx">包装单位</view>
|
||||
<view class="flex flex-wrap px-2">
|
||||
<view class="w-1/2 flex justify-center p-1" v-for="(item, index) in state.detail?.skuList" :key="index">
|
||||
<view class="w-1/2 p-1" v-for="(item, index) in state.detail?.skuList" :key="index">
|
||||
<view class="p-2 w-full bg-#eeeeee77 rounded-2 flex-col second-text-28">
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>单位:</text>
|
||||
<view class="flex mt-1">
|
||||
<text class="w-80rpx mr-1">单位</text>
|
||||
<text>{{ item.spec + " / " + item.unit }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>口味:</text>
|
||||
<view class="flex mt-1">
|
||||
<text class="w-80rpx mr-1">口味</text>
|
||||
<text>{{ item?.attribute || "无" }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>库存:</text>
|
||||
<view class="flex mt-1">
|
||||
<text class="w-80rpx mr-1">库存</text>
|
||||
<text>{{ item?.stock || 0 }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>原价:</text>
|
||||
<text class="line-through">¥ {{ item.retailPrice.toFixed(2) || 0 }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>促销:</text>
|
||||
<text class="c-red!">¥ {{ item.promotionPrice.toFixed(2) || item.retailPrice.toFixed(2) || 0 }}</text>
|
||||
<view class="flex items-end mt-1">
|
||||
<text class="c-red! second-text-32 mr-2">¥{{ item.promotionPrice.toFixed(2) || item.retailPrice.toFixed(2) || 0 }}</text>
|
||||
<text class="line-through">¥{{ item.retailPrice.toFixed(2) || 0 }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- <view class="h-15rpx" />
|
||||
<view class="flex-col justify-between card p-y-20rpx p-x-30rpx">
|
||||
<view class="prefix_title mb-15rpx">评价</view>
|
||||
</view> -->
|
||||
<view class="h-15rpx" />
|
||||
<view class="flex-col justify-between card p-y-20rpx p-x-30rpx">
|
||||
<view class="prefix_title mb-15rpx">详情</view>
|
||||
<view class="flex-col justify-between card py-20rpx px-30rpx">
|
||||
<view class="prefix_title mb-15rpx">详情描述</view>
|
||||
<view class="second-text-28 px-3" v-html="state.detail?.description"></view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -121,8 +107,8 @@ const doCart = async () => {
|
||||
|
||||
<template #main-bottom>
|
||||
<view class="flex-row justify-between items-center my-4 mx-12">
|
||||
<tm-badge bg-color="red" :label="cartStore.totCount">
|
||||
<view class="flex-col-center" @tap="doCart">
|
||||
<tm-badge bg-color="red" :label="cartStore.totalCount">
|
||||
<view class="flex-col-center" @tap="goCart">
|
||||
<view class="color-#0094ff! iconfont icon-biaoqianlanicon_gouwuche-xuanzhong" />
|
||||
<view class="c-#0094ff text-20rpx">购物车</view>
|
||||
</view>
|
||||
@@ -133,7 +119,7 @@ const doCart = async () => {
|
||||
</crud-layout>
|
||||
|
||||
<!-- 单位与数量选择 -->
|
||||
<product-sku v-model="state.showSkuDialog" :productData="state.detail" @onSkuAddToCart="onSkuAddToCart" />
|
||||
<product-sku v-model="state.showSkuDialog" :goodsData="state.detail" @onSkuAddToCart="onSkuAddToCart" />
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -116,12 +116,7 @@ const doCancelRefund = async () => {
|
||||
<view class="flex-col justify-center card p-x-20rpx p-y-30rpx m-b-20rpx">
|
||||
<view class="sub-text-32">商品费用</view>
|
||||
<view class="m-t-15rpx">
|
||||
<view
|
||||
class="flex-row items-start justify-between"
|
||||
v-for="(v, i) in state.shopCarList"
|
||||
:key="i"
|
||||
@tap.stop="router.jump('/pages/merchant/product-detail', { id: v.productId })"
|
||||
>
|
||||
<view class="flex-row items-start justify-between" v-for="(v, i) in state.shopCarList" :key="i">
|
||||
<view class="flex-row items-center">
|
||||
<image class="w-160rpx h-160rpx rounded-8rpx" :src="filePath(v.productPic)" mode="aspectFill" />
|
||||
<view class="flex-col m-l-15rpx second-text-26">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed } from "vue"
|
||||
import { ref, reactive } from "vue"
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app"
|
||||
import { merchantApi } from "@@/api"
|
||||
import { hooks, router } from "@@/index"
|
||||
|
||||
+10
-10
@@ -93,7 +93,7 @@
|
||||
</scroll-view>
|
||||
|
||||
<scroll-view v-if="state.goodsList.length" scroll-y :style="{ height: getHeight() }" class="flex-1 p-b-20rpx p-x-15rpx">
|
||||
<product-row
|
||||
<!-- <product-row
|
||||
v-for="goodsItem in state.goodsList"
|
||||
:key="goodsItem.id"
|
||||
:productId="goodsItem.id"
|
||||
@@ -106,7 +106,7 @@
|
||||
:retailPrice="goodsItem.retailPrice"
|
||||
:promotionPrice="goodsItem.promotionPrice"
|
||||
@onClickAddToCart="onClickAddToCart(goodsItem)"
|
||||
/>
|
||||
/> -->
|
||||
</scroll-view>
|
||||
</view>
|
||||
</tm-sticky>
|
||||
@@ -114,13 +114,13 @@
|
||||
|
||||
<template #main-bottom>
|
||||
<view v-if="false && state.classifyList.length" class="car z-200 p-x-30rpx p-y-30rpx bg-white">
|
||||
<product-total :totPrice="state.totPrice" :totCount="state.totCount" @doContainer="doVisibleCart" @submit="doBuy" />
|
||||
<!-- <product-total :totPrice="state.totPrice" :totCount="state.totCount" @doContainer="doVisibleCart" @submit="doBuy" /> -->
|
||||
</view>
|
||||
</template>
|
||||
</crud-layout>
|
||||
|
||||
<!-- 购物车弹框 -->
|
||||
<product-cart
|
||||
<!-- <product-cart
|
||||
v-model="state.showCartDialog"
|
||||
:cartList="state.cartList"
|
||||
:totPrice="state.totPrice"
|
||||
@@ -128,9 +128,9 @@
|
||||
@add="doAdd"
|
||||
@remove="doRemove"
|
||||
@submit="doBuy"
|
||||
/>
|
||||
/> -->
|
||||
<!-- 规格与数量弹框 -->
|
||||
<product-sku v-model="state.showSkuDialog" :productData="state.curProductData" @onSkuAddToCart="onSkuAddToCart" />
|
||||
<!-- <product-sku v-model="state.showSkuDialog" :productData="state.curProductData" @onSkuAddToCart="onSkuAddToCart" /> -->
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -140,10 +140,10 @@ import { isEmpty } from "radash"
|
||||
import { hooks, router } from "@@/index"
|
||||
import { foodApi, merchantApi, payApi, shopApi } from "@@/api"
|
||||
import { filePath } from "@@/utils/file"
|
||||
import ProductRow from "./components/product-row.vue"
|
||||
import ProductCart from "./components/product-cart.vue"
|
||||
import ProductTotal from "./components/product-total.vue"
|
||||
import ProductSku from "./components/product-sku.vue"
|
||||
// import ProductRow from "./components/product-row.vue"
|
||||
// import ProductCart from "./components/product-cart.vue"
|
||||
// import ProductTotal from "./components/product-total.vue"
|
||||
// import ProductSku from "./components/product-sku.vue"
|
||||
import { getAppInfo } from "@/sheep/utils/app"
|
||||
import { APPENV } from "@/sheep/constant"
|
||||
|
||||
|
||||
@@ -16,12 +16,12 @@
|
||||
:auto="false"
|
||||
>
|
||||
<template #top>
|
||||
<view class="flex justify-between items-center my-1 z-1000">
|
||||
<view class="flex justify-between items-center my-1">
|
||||
<tm-text font-size="40" color="#0779FD" class="font-bold">欢迎选购</tm-text>
|
||||
<view class="flex justify-center items-center" @tap="changeShop">
|
||||
<image class="size-40rpx" src="@/static/page/address-blue.svg" />
|
||||
<tm-text font-size="32" color="#0779FD">{{ state.curMerchant.name }}</tm-text>
|
||||
<image class="size-30rpx ml-1" src="@/static/page/arrow-down-s-fill.svg" />
|
||||
<image class="size-30rpx" src="@/static/page/arrow-down-s-fill.svg" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="w-full flex items-center">
|
||||
@@ -38,13 +38,14 @@
|
||||
style="border: 4rpx solid #0779fd; border-radius: 14rpx"
|
||||
:focus-highlight="false"
|
||||
color="#ECF4F9"
|
||||
@clear="inputClear"
|
||||
>
|
||||
<template v-slot:rightIcon>
|
||||
<tm-button class="mr-1 px-3 py-26rpx text-30rpx!" size="xs" @click="searchProduct">搜 索</tm-button>
|
||||
</template>
|
||||
</tm-input>
|
||||
<tm-badge bg-color="red" :offset="[8, 4]" :label="cartStore.totCount">
|
||||
<view class="flex-col-center size-80rpx" @tap="doCart">
|
||||
<tm-badge bg-color="red" :offset="[8, 4]" :label="cartStore.totalCount">
|
||||
<view class="flex-col-center size-80rpx" @tap="goCart">
|
||||
<view class="color-#0094ff! iconfont icon-biaoqianlanicon_gouwuche-xuanzhong" />
|
||||
<view class="c-#0094ff text-22rpx">购物车</view>
|
||||
</view>
|
||||
@@ -55,9 +56,9 @@
|
||||
<view
|
||||
class="mr-2 sub-text-28 py-1 px-2 rounded-1 bg-#fff border border-solid border-transparent whitespace-nowrap"
|
||||
:class="{ 'bg-#0779FD22! c-#0779FD! border-#0779FD33!': state.params.categoryId === v.id }"
|
||||
v-for="(v, i) in state.classifyList"
|
||||
v-for="(v, i) in state.categaryList"
|
||||
:key="i"
|
||||
@tap="doClassify(v.id)"
|
||||
@tap="changeCategary(v.id)"
|
||||
>
|
||||
{{ v.name }}
|
||||
</view>
|
||||
@@ -79,18 +80,16 @@
|
||||
:animationCancel="false"
|
||||
>
|
||||
<template #default="{ item, url, index }">
|
||||
<view class="card" @click="toDetail(item)">
|
||||
<view class="card" @click="goDetail(item)">
|
||||
<LazyImg class="rounded-2" :url="filePath(item.picUrl)" />
|
||||
<view class="p-16rpx flex-col">
|
||||
<view class="sub-text-32 show-line">{{ item.productName }}</view>
|
||||
<view class="second-text-26 flex justify-between">
|
||||
<view>{{ item.productNature == "2" ? "电子称重商品" : "普通商品" }}</view>
|
||||
<view>已售 {{ item.salesCount || 0 }}</view>
|
||||
</view>
|
||||
<view class="flex-row justify-between items-center">
|
||||
<view class="flex items-center">
|
||||
<view class="second-text-32 c-red!">¥ {{ storePrice(item.minPrice).toFixed(2) }}</view>
|
||||
<!-- <view v-if="parseFloat(item.promotionPrice) != 0" class="ml-10rpx second-text-30 line-through">
|
||||
¥{{ hooks.useMoney(item.retailPrice) || 0 }}
|
||||
</view> -->
|
||||
</view>
|
||||
<view class="second-text-26">已售:{{ item.salesCount || 0 }}</view>
|
||||
<view class="second-text-32 c-red!">¥{{ displayPrice(item.minPrice, "") }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -102,7 +101,7 @@
|
||||
:showClose="false"
|
||||
:showFooter="true"
|
||||
size="70%"
|
||||
v-model:show="state.showDrawer"
|
||||
v-model:show="state.shopDrawerShow"
|
||||
:duration="100"
|
||||
zIndex="1200"
|
||||
>
|
||||
@@ -113,14 +112,14 @@
|
||||
class="w-full flex items-center p-2 rounded-3"
|
||||
:class="[state.curMerchantRadioId == item.id ? 'bg-#e8e8e8' : '']"
|
||||
>
|
||||
<tm-radio class="w-full h-full px-2" :value="item.id">
|
||||
<tm-radio :value="item.id">
|
||||
<template v-slot:label="checked">
|
||||
<view class="flex items-center">
|
||||
<image class="w-130rpx h-130rpx rounded-2" :src="filePath(item.logoPic)" mode="aspectFill" />
|
||||
<image class="size-130rpx rounded-2" :src="filePath(item.logoPic)" mode="aspectFill" />
|
||||
<view class="ml-2 flex-1 flex-col">
|
||||
<tm-text font-size="30">{{ item.name }}</tm-text>
|
||||
<view class="second-text-26">地址:{{ item.addressDes }}</view>
|
||||
<view class="second-text-26">手机:{{ item.phone }}</view>
|
||||
<view class="second-text-26">地址 {{ item.addressDes }}</view>
|
||||
<view class="second-text-26">手机 {{ item.phone }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -130,7 +129,7 @@
|
||||
|
||||
<template #footer>
|
||||
<view class="px-20rpx pt-2 flex justify-between">
|
||||
<tm-button skin="thin" block @click="state.showDrawer = false">取消</tm-button>
|
||||
<tm-button skin="thin" block @click="state.shopDrawerShow = false">取消</tm-button>
|
||||
|
||||
<tm-button block @click="confirmRadioMerchant">确定</tm-button>
|
||||
</view>
|
||||
@@ -141,7 +140,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { ref, reactive } from "vue"
|
||||
import { LazyImg, Waterfall } from "vue-waterfall-plugin-next"
|
||||
import "vue-waterfall-plugin-next/dist/style.css"
|
||||
@@ -150,7 +149,7 @@ import { filePath } from "@@/utils/file"
|
||||
import { merchantApi, onlineShopApi } from "@@/api"
|
||||
import { hooks, router } from "@@/index"
|
||||
import { useCartStore } from "@/sheep/stores/cart"
|
||||
import { storePrice } from "@/sheep/utils/formatMoney"
|
||||
import { displayPrice } from "@/sheep/utils/formatMoney"
|
||||
import treeToList from "@/sheep/utils/tree-to-list"
|
||||
|
||||
const cartStore = useCartStore()
|
||||
@@ -165,9 +164,9 @@ const state = reactive<any>({
|
||||
|
||||
merchantList: [],
|
||||
curMerchant: {},
|
||||
classifyList: [],
|
||||
categaryList: [],
|
||||
|
||||
showDrawer: false,
|
||||
shopDrawerShow: false,
|
||||
curMerchantRadioId: "",
|
||||
})
|
||||
const pageRef = ref<any>(null)
|
||||
@@ -181,27 +180,19 @@ onLoad(async () => {
|
||||
await cartStore.getShopCart()
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
// pageRef.value && pageRef.value.reload(false)
|
||||
})
|
||||
|
||||
// 获取所有商户
|
||||
const getAllMerchant = async () => {
|
||||
uni.showLoading({ title: "加载中...", mask: true })
|
||||
try {
|
||||
const { code, data }: any = await merchantApi.page({ current: 1, pagesize: 9999999, type: "3" })
|
||||
if (code == 0) {
|
||||
state.merchantList = data.records
|
||||
if (!isEmpty(state.merchantList)) {
|
||||
state.curMerchant = state.merchantList[0]
|
||||
state.params.merchantId = state.curMerchant.id
|
||||
cartStore.saveShopMerchantId(state.curMerchant.id)
|
||||
return
|
||||
}
|
||||
state.curMerchant = {}
|
||||
}
|
||||
if (code != 0) return uni.showToast({ title: "商户获取失败", icon: "error" })
|
||||
state.merchantList = data.records ?? []
|
||||
state.curMerchant = state.merchantList[0] ?? {}
|
||||
state.params.merchantId = state.curMerchant.id
|
||||
cartStore.saveShopMerchantId(state.curMerchant.id)
|
||||
} catch (error) {
|
||||
state.merchantList = []
|
||||
state.curMerchant = {}
|
||||
} finally {
|
||||
uni.hideLoading()
|
||||
}
|
||||
@@ -209,27 +200,26 @@ const getAllMerchant = async () => {
|
||||
|
||||
// 获取分类
|
||||
const getClassify = async () => {
|
||||
if (state.curMerchant.id) {
|
||||
const { data } = await onlineShopApi.getSpuCategory()
|
||||
state.classifyList = treeToList(data) ?? []
|
||||
state.classifyList.unshift({ id: "", name: "全部分类" })
|
||||
if (!isEmpty(state.classifyList)) {
|
||||
state.params.categoryId = state.classifyList[0].id
|
||||
pageRef.value && pageRef.value.reload(false)
|
||||
}
|
||||
if (!state.curMerchant.id) return
|
||||
const { data } = await onlineShopApi.getSpuCategory()
|
||||
state.categaryList = treeToList(data) ?? []
|
||||
state.categaryList.unshift({ id: "", name: "全部分类" })
|
||||
if (!isEmpty(state.categaryList)) {
|
||||
state.params.categoryId = state.categaryList[0].id
|
||||
pageRef.value && pageRef.value.reload(false)
|
||||
}
|
||||
}
|
||||
|
||||
// 切换超市
|
||||
// 打开切换超市抽屉
|
||||
const changeShop = () => {
|
||||
state.curMerchantRadioId = state.curMerchant.id || ""
|
||||
state.showDrawer = true
|
||||
state.shopDrawerShow = true
|
||||
}
|
||||
|
||||
// 确定切换超市
|
||||
const confirmRadioMerchant = async () => {
|
||||
state.curMerchant = state.merchantList.find((item: any) => item.id == state.curMerchantRadioId)
|
||||
state.showDrawer = false
|
||||
state.shopDrawerShow = false
|
||||
state.params.merchantId = state.curMerchant.id
|
||||
cartStore.saveShopMerchantId(state.curMerchant.id)
|
||||
await cartStore.getShopCart()
|
||||
@@ -238,34 +228,33 @@ const confirmRadioMerchant = async () => {
|
||||
|
||||
// 点击搜索
|
||||
const searchProduct = () => {
|
||||
state.params.categoryId = ""
|
||||
pageRef.value && pageRef.value.reload(false)
|
||||
}
|
||||
|
||||
// 切换分类
|
||||
const doClassify = async (categoryId: string) => {
|
||||
const changeCategary = async (categoryId: string) => {
|
||||
if (state.params.categoryId == categoryId) return
|
||||
state.params.categoryId = categoryId
|
||||
pageRef.value && pageRef.value.reload(false)
|
||||
}
|
||||
|
||||
const inputClear = () => {
|
||||
pageRef.value && pageRef.value.reload(false)
|
||||
}
|
||||
|
||||
const pageHook = hooks.usePage(pageRef, onlineShopApi.getSpuList, null, "data.records")
|
||||
|
||||
const query = (page: number, pagesize: number) => {
|
||||
pageHook.startPage(page, pagesize, false, state.params)
|
||||
}
|
||||
|
||||
const toDetail = async (v: any) => {
|
||||
const goDetail = async (v: any) => {
|
||||
const isLogin = await hooks.useCheckLogin()
|
||||
if (isLogin) {
|
||||
router.jump("/pages/shop/product-detail", { id: v.id })
|
||||
}
|
||||
if (isLogin) router.jump("/pages/online-shop/goods-detail", { id: v.id })
|
||||
}
|
||||
|
||||
const doCart = async () => {
|
||||
const goCart = async () => {
|
||||
const isLogin = await hooks.useCheckLogin()
|
||||
if (isLogin) {
|
||||
router.jump("/pages/shop/cart")
|
||||
}
|
||||
if (isLogin) router.jump("/pages/online-shop/cart")
|
||||
}
|
||||
</script>
|
||||
@@ -1,75 +0,0 @@
|
||||
<template>
|
||||
<crud-layout bg="/static/page/blue-bg.png">
|
||||
<z-paging
|
||||
ref="pageRef"
|
||||
height="100%"
|
||||
:fixed="false"
|
||||
v-model="pageHook.list"
|
||||
:default-page-size="10"
|
||||
safe-area-inset-bottom
|
||||
:loading-more-enabled="true"
|
||||
:show-scrollbar="false"
|
||||
@query="query"
|
||||
:auto-clean-list-when-reload="false"
|
||||
:auto-scroll-to-top-when-reload="false"
|
||||
@scroll="pageHook.scroll"
|
||||
>
|
||||
<view class="h-30rpx" />
|
||||
<tm-sheet v-if="false" v-for="(item, index) in pageHook.list" :key="index" :margin="[0, 20]">
|
||||
<view class="text-36 overflow-hidden text-nowrap text-ellipsis">
|
||||
文本TmText文本TmText文本TmText文本TmText文本TmText文本TmText文本TmText文本TmText文本TmText文本TmText文本TmText文本
|
||||
</view>
|
||||
<view class="flex items-center">
|
||||
<image src="@/static/page/时间.svg" mode="aspectFill" class="w-28rpx h-28rpx mr-1" />
|
||||
<tm-text font-size="26">2025-06-06</tm-text>
|
||||
</view>
|
||||
<swiper class="my-1" circular :indicator-dots="false" indicator-active-color="#0779FD" indicator-color="#ffffff" :autoplay="true">
|
||||
<swiper-item>
|
||||
<image
|
||||
class="w-full h-full"
|
||||
:src="'https://stgl.pj.gov.cn/api/admin/sys-file/oss/file?fileName=3378726f7c4b40128c238c8827d6350e.jpg'"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<tm-text
|
||||
@item-click="doDetail(item.id)"
|
||||
class="line-10"
|
||||
:heightLight="['高亮显示', '正则', '邮箱']"
|
||||
label="支持多文本高亮显示,比如根据正则高亮电话号码,邮箱等,点击后打电话,发邮件。"
|
||||
/>
|
||||
</tm-sheet>
|
||||
</z-paging>
|
||||
</crud-layout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue"
|
||||
import { hooks, router } from "@/sheep"
|
||||
import { doorApi } from "@/sheep/api"
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app"
|
||||
|
||||
const pageRef = ref<any>(null)
|
||||
|
||||
onLoad(() => {
|
||||
const app = getApp()
|
||||
app._initTabbar()
|
||||
})
|
||||
onShow(() => {
|
||||
if (pageRef.value) {
|
||||
pageRef.value.reload(false)
|
||||
}
|
||||
})
|
||||
|
||||
const pageHook = hooks.usePage(pageRef, doorApi.hardDoorPage, null, "data.records")
|
||||
|
||||
const query = (page: number, pagesize: number) => {
|
||||
pageHook.startPage(page, pagesize, false, {})
|
||||
}
|
||||
|
||||
// 公告详情
|
||||
const doDetail = (id: string) => {
|
||||
if (!id) return
|
||||
router.jump("/pages/cabinet/cabinetDetail", { id }, 1)
|
||||
}
|
||||
</script>
|
||||
@@ -1,82 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from "vue"
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app"
|
||||
import { merchantApi } from "@@/api"
|
||||
import { hooks, router } from "@@/index"
|
||||
import { filePath } from "@@/utils/file"
|
||||
|
||||
const pageRef = ref<any>(null)
|
||||
const state = reactive<any>({
|
||||
pa: {
|
||||
pagesize: 10,
|
||||
type: "3",
|
||||
},
|
||||
})
|
||||
const pageHook = hooks.usePage(pageRef, merchantApi.page, null, "data.records")
|
||||
|
||||
const query = (page: number, pagesize: number) => {
|
||||
pageHook.startPage(page, pagesize, false, state.pa)
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
const app = getApp()
|
||||
app._initTabbar()
|
||||
})
|
||||
onShow(() => {
|
||||
pageRef.value && pageRef.value.reload(false)
|
||||
})
|
||||
|
||||
const toDetail = async (v: any) => {
|
||||
const isLogin = await hooks.useCheckLogin()
|
||||
if (isLogin) {
|
||||
router.jump("/pages/shop/detail", { id: v.id })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<crud-layout bg="/static/page/blue-bg.png">
|
||||
<z-paging
|
||||
ref="pageRef"
|
||||
height="100%"
|
||||
:fixed="false"
|
||||
v-model="pageHook.list"
|
||||
:default-page-size="10"
|
||||
safe-area-inset-bottom
|
||||
:loading-more-enabled="true"
|
||||
:show-scrollbar="false"
|
||||
@query="query"
|
||||
:auto-clean-list-when-reload="false"
|
||||
:auto-scroll-to-top-when-reload="false"
|
||||
@scroll="pageHook.scroll"
|
||||
>
|
||||
<view class="h-20rpx" />
|
||||
<view class="flex-row card p-20rpx m-b-20rpx" v-for="(v, i) in pageHook.list" :key="i" @tap="toDetail(v)">
|
||||
<image class="w-180rpx h-180rpx rounded-12rpx" :src="filePath(v.logoPic)" mode="aspectFill" />
|
||||
<view class="flex-1 flex-col m-l-20rpx">
|
||||
<view class="flex-row items-center justify-between">
|
||||
<view class="flex-row-center sub-text-34">{{ v.name }}</view>
|
||||
<tm-tag size="s">{{ v.deptName }}</tm-tag>
|
||||
</view>
|
||||
<view class="m-t-10rpx">
|
||||
<view v-if="v.phone" class="flex items-center">
|
||||
<image class="w-24rpx h-24rpx" src="@/static/page/phone.svg" />
|
||||
<view class="second-text-28 ml-1">{{ v.phone }}</view>
|
||||
</view>
|
||||
<view class="second-text-24">
|
||||
<view class="second-text-28">{{ v.jobTime == ",," ? "" : "营业时间:" }}</view>
|
||||
<view>{{ v.jobTime?.split(",")[0] ? "早:" + v.jobTime?.split(",")[0] : "" }}</view>
|
||||
<view>{{ v.jobTime?.split(",")[1] ? "中:" + v.jobTime?.split(",")[1] : "" }}</view>
|
||||
<view>{{ v.jobTime?.split(",")[2] ? "晚:" + v.jobTime?.split(",")[2] : "" }}</view>
|
||||
</view>
|
||||
<view v-if="v.addressDes" class="second-text-28">
|
||||
<image class="w-24rpx h-24rpx" src="@/static/page/address.svg" />
|
||||
<text class="ml-1">地址:</text>
|
||||
<text class="m-l-10rpx">{{ v.addressDes }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</z-paging>
|
||||
</crud-layout>
|
||||
</template>
|
||||
@@ -3,11 +3,11 @@ import { foodApi } from "../api"
|
||||
|
||||
export const useCartStore = defineStore("cartStore", {
|
||||
state: () => ({
|
||||
cart: JSON.parse(uni.getStorageSync("cart") || "[]"),
|
||||
shopMerchantId: uni.getStorageSync("shopMerchantId") || "",
|
||||
cart: JSON.parse(uni.getStorageSync("onlineShopCart") || "[]"),
|
||||
shopMerchantId: uni.getStorageSync("onlineShopMerchantId") || "",
|
||||
}),
|
||||
getters: {
|
||||
totCount(state) {
|
||||
totalCount(state) {
|
||||
return state.cart.reduce((prev: string, cur: any) => {
|
||||
return prev + cur.productCount
|
||||
}, 0)
|
||||
@@ -22,14 +22,11 @@ export const useCartStore = defineStore("cartStore", {
|
||||
actions: {
|
||||
saveShopMerchantId(shopMerchantId: string) {
|
||||
this.shopMerchantId = shopMerchantId
|
||||
uni.setStorageSync("shopMerchantId", this.shopMerchantId)
|
||||
uni.setStorageSync("onlineShopMerchantId", this.shopMerchantId)
|
||||
},
|
||||
saveToStorage() {
|
||||
uni.setStorageSync("cart", JSON.stringify(this.cart))
|
||||
},
|
||||
saveShoppingCart(cartList: any) {
|
||||
saveShopCart(cartList: any) {
|
||||
this.cart = cartList
|
||||
this.saveToStorage()
|
||||
uni.setStorageSync("onlineShopCart", JSON.stringify(this.cart))
|
||||
},
|
||||
addGoodsItemToCart(goodsItem: any) {
|
||||
const findResult = this.cart.find((item: any) => {
|
||||
@@ -40,7 +37,7 @@ export const useCartStore = defineStore("cartStore", {
|
||||
} else {
|
||||
findResult.productCount++
|
||||
}
|
||||
this.saveToStorage()
|
||||
uni.setStorageSync("onlineShopCart", JSON.stringify(this.cart))
|
||||
},
|
||||
async addProductCount(productId: string) {
|
||||
this.cart.forEach((item: any) => {
|
||||
@@ -62,7 +59,7 @@ export const useCartStore = defineStore("cartStore", {
|
||||
},
|
||||
async getShopCart() {
|
||||
const { data } = await foodApi.getShopCar({ merchantId: this.shopMerchantId, hardType: "SUPERMARKET" })
|
||||
this.saveShoppingCart(data ?? [])
|
||||
this.saveShopCart(data ?? [])
|
||||
},
|
||||
async updateShopCart() {
|
||||
const list = this.cart
|
||||
|
||||
Reference in new issue
Block a user