| | |
| | | "componentPlaceholder": { |
| | | "u-icon": "view", |
| | | "u-navbar": "view", |
| | | "u-popup": "view" |
| | | "u-popup": "view", |
| | | "popups":"view" |
| | | } |
| | | } |
| | | }, |
| | |
| | | { |
| | | "navigationBarTitleText" : "分包占位" |
| | | } |
| | | },{ |
| | | "path" : "popups/popups", |
| | | "style" : |
| | | { |
| | | "componentPlaceholder": { |
| | | "u-modal": "view", |
| | | "u-tabs": "view", |
| | | "u-image": "view", |
| | | "u-search": "view", |
| | | "u-icon": "view", |
| | | "u-loadmore": "view" |
| | | } |
| | | } |
| | | } |
| | | ] |
| | | }, |
| | |
| | | </scroll-view> |
| | | |
| | | </view> |
| | | <view class="goodsInfos"> |
| | | <scroll-view :scroll-y="true" :show-scrollbar="false"> |
| | | <view class="goodsInfos" > |
| | | <scroll-view :scroll-y="true" :show-scrollbar="false" style="height: 100%;"> |
| | | |
| | | <view class="goodsItem" v-for="item in goodsList" :key="item.id" |
| | | @click.prevent="goToGoodsInfo(item.id)" |
| | |
| | | <Evaluation id="main5" :goodsDetail="goodsDetail" /> |
| | | |
| | | <!-- 店铺推荐 --> |
| | | <storeLayout id="main7" :storeDetail="storeDetail" :goodsDetail="goodsDetail" :res="recommendList" /> |
| | | <!-- <storeLayout id="main7" :storeDetail="storeDetail" :goodsDetail="goodsDetail" :res="recommendList" /> --> |
| | | |
| | | <!-- 宝贝详情 --> |
| | | <GoodsIntro id="main9" :res="goodsDetail" :goodsParams="goodsParams" :goodsId="goodsDetail.goodsId" |
| | | v-if="goodsDetail.id" /> |
| | | |
| | | <!-- 宝贝推荐 --> |
| | | <GoodsRecommend id="main11" :res="likeGoodsList" /> |
| | | <!-- <GoodsRecommend id="main11" :res="likeGoodsList" /> --> |
| | | </view> |
| | | </scroll-view> |
| | | |
| | | |
| | | <view class="page-bottom mp-iphonex-bottom" id="pageBottom"> |
| | | <view class="icon-btn"> |
| | | <view class="icon-btn-item" @click="navigateToStore(goodsDetail.storeId)"> |
| | | <!-- <view class="icon-btn-item" @click="navigateToStore(goodsDetail.storeId)"> |
| | | <u-icon size="34" class="red" name="home-fill"></u-icon> |
| | | <view class="red icon-btn-name">店铺</view> |
| | | </view> |
| | | </view> --> |
| | | <view class="icon-btn-item" @click="linkMsgDetail()"> |
| | | <u-icon size="34" name="kefu-ermai"></u-icon> |
| | | <view class="icon-btn-name">客服</view> |
| | |
| | | import PromotionAssembleListLayout from "./product/promotion/-promotion-assemble-list"; //拼团用户列表 |
| | | import PromotionCoupon from "./product/promotion/-promotion-coupon"; //优惠券组件 |
| | | import GoodsIntro from "./product/goods/-goods-intro"; //商品介绍组件 |
| | | import GoodsRecommend from "./product/goods/-goods-recommend"; //宝贝推荐 |
| | | // import GoodsRecommend from "./product/goods/-goods-recommend"; //宝贝推荐 |
| | | import storeLayout from "./product/shop/-shop"; //店铺组件 |
| | | import Evaluation from "./product/evaluation/-evaluation"; //评价组件 |
| | | import GoodsSwiper from "./product/goods/-goods-swiper"; //轮播图组件 |
| | | import popupGoods from "@/pages/product/m-buy/goods.vue"; //购物车商品的模块 |
| | | import popupAddress from "./product/popup/address"; //地址选择模块 |
| | | import shares from "@/pages/product/m-share/index.vue"; //分享 |
| | | import popups from "@/pages/product/popups/popups.vue"; //气泡框 |
| | | import popups from "@/pages/subComponents/popups/popups.vue"; //气泡框 |
| | | import takeDownFormSaleGoods from "@/pages/product/m-take-down-sale-goods/index"; //下架框 |
| | | import setup from "./product/popup/popup"; |
| | | import { |
| | |
| | | PromotionAssembleListLayout, |
| | | PromotionCoupon, |
| | | GoodsIntro, |
| | | GoodsRecommend, |
| | | storeLayout, |
| | | Evaluation, |
| | | GoodsSwiper, |
| New file |
| | |
| | | ## 商品列表展示 |
| | | |
| | | ### OBJECT 参数说明 |
| | | |
| | | | 属性 | 说明 | 类型 | 必填 | |
| | | | ----------- | ---------------------------------------------------------- | ------- | ---- | |
| | | | `res` | 显示数据 | Array | 是 | |
| | | | `type` | 商品展示类型 oneColumns twoColumns ,默认展示一行两列商品 | String | 否 | |
| | | | `storeName` | 是否展示店铺名称,默认展示 | Boolean | 否 | |
| | | | `keywords` | 高亮展示搜索内容 | String | 否 | |
| | | |
| New file |
| | |
| | | <template> |
| | | <div> |
| | | <!-- 一行两列商品展示 --> |
| | | <view class="goods-list" v-if="type == 'twoColumns'"> |
| | | <view v-for="(item, index) in res" :key="index" class="goods-item"> |
| | | <view class="image-wrapper" @click="navigateToDetailPage(item)"> |
| | | <u-image |
| | | :src="item.thumbnail" |
| | | width="100%" |
| | | height="330rpx" |
| | | mode="aspectFit" |
| | | > |
| | | <u-loading slot="loading"></u-loading> |
| | | </u-image> |
| | | </view> |
| | | <view class="goods-detail"> |
| | | <div |
| | | class="title clamp" |
| | | v-html="lightSearchStr(keyword, item.goodsName)" |
| | | @click="navigateToDetailPage(item)" |
| | | ></div> |
| | | <view class="price-box" @click="navigateToDetailPage(item)"> |
| | | <div class="price" v-if="item.price != undefined"> |
| | | ¥<span |
| | | >{{ |
| | | $options.filters.goodsFormatPrice(item.price)[0] |
| | | }} </span |
| | | >.{{ $options.filters.goodsFormatPrice(item.price)[1] }} |
| | | </div> |
| | | </view> |
| | | <div class="count-config" @click="navigateToDetailPage(item)"> |
| | | <span>已售 {{ item.buyCount || "0" }}</span> |
| | | <span>{{ item.commentNum || "0" }}条评论</span> |
| | | </div> |
| | | <div |
| | | class="store-seller-name" |
| | | v-if="storeName" |
| | | @click="navigateToStoreDetailPage(item)" |
| | | > |
| | | <div class="text-hidden"> |
| | | <u-tag |
| | | style="margin-right: 10rpx" |
| | | size="mini" |
| | | mode="dark" |
| | | v-if="item.selfOperated" |
| | | text="自营" |
| | | type="error" |
| | | /> |
| | | <span>{{ item.storeName || "暂无" }}</span> |
| | | </div> |
| | | <span> |
| | | <u-icon name="arrow-right"></u-icon> |
| | | </span> |
| | | </div> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- 一行一列商品展示 --> |
| | | <div v-if="type == 'oneColumns'"> |
| | | <div v-for="(item, index) in res" :key="index" class="goods-row"> |
| | | <div class="flex goods-col"> |
| | | <div class="goods-img" @click="navigateToDetailPage(item)"> |
| | | <u-image |
| | | width="230rpx" |
| | | border-radius="16" |
| | | height="230rpx" |
| | | mode="aspectFit" |
| | | :src="item.goodsImage || item.thumbnail" |
| | | > |
| | | <u-loading slot="loading"></u-loading> |
| | | </u-image> |
| | | </div> |
| | | <div class="goods-detail"> |
| | | <div class="title clamp3" @click="navigateToDetailPage(item)"> |
| | | {{ item.goodsName }} |
| | | </div> |
| | | <view class="price-box" @click="navigateToDetailPage(item)"> |
| | | <div class="price" v-if="item.price != undefined"> |
| | | ¥<span |
| | | >{{ $options.filters.goodsFormatPrice(item.price)[0] }} </span |
| | | >.{{ $options.filters.goodsFormatPrice(item.price)[1] }} |
| | | </div> |
| | | </view> |
| | | <div class="promotion" @click="navigateToDetailPage(item)"> |
| | | <div v-if="item.salesModel == 'WHOLESALE'"> |
| | | <span>批</span> |
| | | </div> |
| | | <div |
| | | v-for="(promotionItem, promotionIndex) in getPromotion(item)" |
| | | :key="promotionIndex" |
| | | > |
| | | <span v-if="promotionItem.indexOf('COUPON') != -1">劵</span> |
| | | <span v-if="promotionItem.indexOf('FULL_DISCOUNT') != -1" |
| | | >满减</span |
| | | > |
| | | <span v-if="promotionItem.indexOf('SECKILL') != -1">秒杀</span> |
| | | </div> |
| | | </div> |
| | | <div |
| | | style="overflow: hidden" |
| | | @click="navigateToDetailPage(item)" |
| | | class="count-config" |
| | | > |
| | | <span style="float: left; font-size: 22rpx" |
| | | >已售 {{ item.buyCount || "0" }}</span |
| | | > |
| | | <span style="float: right; font-size: 22rpx" |
| | | >{{ item.commentNum || "0" }}条评论</span |
| | | > |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import commonTpl from "@/pages/product/m-goods-list/common.vue"; |
| | | export default { |
| | | data() { |
| | | return { |
| | | lightColor: this.$mainColor, |
| | | }; |
| | | }, |
| | | mixins: [commonTpl], |
| | | props: { |
| | | // 展示的类型 |
| | | type:{ |
| | | type:String, |
| | | default:"oneColumns" |
| | | }, |
| | | // 遍历的数据 |
| | | res: { |
| | | type: Array, |
| | | default: () => { |
| | | return []; |
| | | }, |
| | | }, |
| | | }, |
| | | methods: { |
| | | // 跳转到商品详情 |
| | | navigateToDetailPage(item) { |
| | | uni.navigateTo({ |
| | | url: `/pages/product/goods?id=${item.id}&goodsId=${item.goodsId}`, |
| | | }); |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .goods-list { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | margin: 10rpx 20rpx 284rpx; |
| | | width: 100%; |
| | | |
| | | > .goods-item { |
| | | background-color: #ffffff; |
| | | display: flex; |
| | | border-radius: 16rpx; |
| | | flex-direction: column; |
| | | width: calc(50% - 30rpx); |
| | | margin-bottom: 20rpx; |
| | | padding-bottom: 20rpx; |
| | | |
| | | &:nth-child(2n + 1) { |
| | | margin-right: 20rpx; |
| | | } |
| | | |
| | | .image-wrapper { |
| | | width: 100%; |
| | | height: 330rpx; |
| | | border-radius: 16rpx 16rpx 0 0; |
| | | overflow: hidden; |
| | | padding: 0; |
| | | } |
| | | } |
| | | |
| | | .count-config, |
| | | .store-seller-name { |
| | | font-size: $font-sm; |
| | | } |
| | | |
| | | .text-hidden { |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | } |
| | | |
| | | .goods-row { |
| | | background: #fff; |
| | | padding: 16rpx; |
| | | |
| | | > .goods-col { |
| | | display: flex; |
| | | |
| | | > .goods-img { |
| | | overflow: hidden; |
| | | flex: 4; |
| | | } |
| | | |
| | | > .goods-detail { |
| | | flex: 7; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .goods-detail { |
| | | margin: 0 20rpx; |
| | | |
| | | > .title { |
| | | font-size: $font-base; |
| | | color: $font-color-dark; |
| | | line-height: 1.5; |
| | | height: 86rpx; |
| | | padding: 10rpx 0 0; |
| | | display: -webkit-box; |
| | | -webkit-box-orient: vertical; |
| | | -webkit-line-clamp: 2; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .promotion { |
| | | margin-top: 4rpx; |
| | | display: flex; |
| | | |
| | | div { |
| | | span { |
| | | font-size: 24rpx; |
| | | color: $light-color; |
| | | margin-right: 10rpx; |
| | | padding: 0 4rpx; |
| | | border-radius: 2rpx; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .store-seller-name { |
| | | color: #666; |
| | | overflow: hidden; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .count-config { |
| | | padding: 5rpx 0; |
| | | color: #666; |
| | | display: flex; |
| | | font-size: 24rpx; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | > .price-box { |
| | | margin-top: 10rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding-right: 10rpx; |
| | | font-size: 24rpx; |
| | | color: $font-color-light; |
| | | |
| | | > .price { |
| | | font-size: 26rpx; |
| | | line-height: 1; |
| | | color: $main-color; |
| | | font-weight: bold; |
| | | |
| | | /deep/ span:nth-of-type(1) { |
| | | font-size: 38rpx; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | methods: { |
| | | // 高亮显示搜索内容 |
| | | lightSearchStr(keyword, str) { |
| | | if (!keyword) { |
| | | return str |
| | | } else { |
| | | let unicodes = ''; |
| | | for (let i of Array.from(keyword)) { |
| | | unicodes += this.unicode(i) + "|" |
| | | } |
| | | const rule = '(' + unicodes + ')' |
| | | const reg = new RegExp(rule, 'gi'); |
| | | return str ? str.replace(reg, matchValue => |
| | | `<span style="color:${this.lightColor}">${matchValue}</span>` |
| | | ) : '' |
| | | } |
| | | }, |
| | | // 转换为unicode |
| | | unicode(str) { |
| | | var value = ''; |
| | | for (var i = 0; i < str.length; i++) { |
| | | value += '\\u' + this.left_zero_4(parseInt(str.charCodeAt(i)).toString(16)); |
| | | } |
| | | return value; |
| | | }, |
| | | left_zero_4(str) { |
| | | if (str != null && str != '' && str != 'undefined') { |
| | | if (str.length == 2) { |
| | | return '00' + str; |
| | | } |
| | | } |
| | | return str; |
| | | }, |
| | | // 数据去重一下 只显示一次 减免 劵 什么的 |
| | | getPromotion(item) { |
| | | if (item.promotionMap) { |
| | | let array = []; |
| | | Object.keys(item.promotionMap).forEach((child) => { |
| | | if (!array.includes(child.split("-")[0])) { |
| | | array.push(child.split("-")[0]); |
| | | } |
| | | }); |
| | | return array; |
| | | } |
| | | }, |
| | | // 跳转到商品详情 |
| | | navigateToDetailPage(item) { |
| | | uni.navigateTo({ |
| | | url: `/pages/product/goods?id=${item.id}&goodsId=${item.goodsId}`, |
| | | }); |
| | | }, |
| | | // 跳转地址 |
| | | navigateToStoreDetailPage(item) { |
| | | uni.navigateTo({ |
| | | url: `/pages/product/shopPage?id=${item.storeId}`, |
| | | }); |
| | | }, |
| | | }, |
| | | } |
| | | </script> |
| | | |
| | | <style lang='scss' scoped> |
| | | |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <view> |
| | | <!-- 一行两列商品展示 --> |
| | | <view class="goods-list" v-if="type == 'twoColumns'"> |
| | | <view v-for="(item, index) in res" :key="index" class="goods-item"> |
| | | <view class="image-wrapper" @click="navigateToDetailPage(item)"> |
| | | <u-image :src="item.thumbnail" width="100%" height='330rpx' mode="aspectFit"> |
| | | <u-loading slot="loading"></u-loading> |
| | | </u-image> |
| | | </view> |
| | | <view class="goods-detail"> |
| | | <div class="title clamp" v-html="lightSearchStr(keyword,item.goodsName)" |
| | | @click="navigateToDetailPage(item)"> |
| | | |
| | | </div> |
| | | <view class="price-box" @click="navigateToDetailPage(item)"> |
| | | <div class="price" v-if="item.price!=undefined"> |
| | | ¥<span>{{ $options.filters.goodsFormatPrice(item.price )[0] }} </span>.{{ |
| | | $options.filters.goodsFormatPrice(item.price )[1] |
| | | }} |
| | | </div> |
| | | </view> |
| | | <div class="promotion" @click="navigateToDetailPage(item)"> |
| | | <div v-if="item.salesModel == 'WHOLESALE'"> |
| | | <span>批</span> |
| | | </div> |
| | | <div v-for="(promotionItem,promotionIndex) in getPromotion(item)" :key="promotionIndex"> |
| | | <span v-if="promotionItem.indexOf('COUPON') != -1">劵</span> |
| | | <span v-if="promotionItem.indexOf('FULL_DISCOUNT') != -1">满减</span> |
| | | <span v-if="promotionItem.indexOf('SECKILL') != -1">秒杀</span> |
| | | </div> |
| | | </div> |
| | | <div class="count-config" @click="navigateToDetailPage(item)"> |
| | | <span>已售 {{ item.buyCount || "0" }}</span> |
| | | <span>{{ item.commentNum || "0" }}条评论</span> |
| | | </div> |
| | | <div class="store-seller-name" v-if="storeName" @click="navigateToStoreDetailPage(item)"> |
| | | <div class="text-hidden"> |
| | | <u-tag style="margin-right: 10rpx" size="mini" mode="dark" v-if="item.selfOperated" |
| | | text="自营" type="error" /> |
| | | <span>{{ item.storeName || "暂无" }}</span> |
| | | </div> |
| | | <span> |
| | | <u-icon name="arrow-right"></u-icon> |
| | | </span> |
| | | </div> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- 一行一列商品展示 --> |
| | | <div v-if="type == 'oneColumns'" class="goods-one-row"> |
| | | <div v-for="(item, index) in res" :key="index" class="goods-row"> |
| | | <div class="flex goods-col"> |
| | | <div class="goods-img" @click="navigateToDetailPage(item)"> |
| | | <u-image width="230rpx" mode="aspectFit" border-radius='16' height="230rpx" :src="item.thumbnail"> |
| | | <u-loading slot="loading"></u-loading> |
| | | </u-image> |
| | | </div> |
| | | <div class="goods-detail"> |
| | | <div class="title clamp3" @click="navigateToDetailPage(item)">{{ item.goodsName }}</div> |
| | | <view class="price-box" @click="navigateToDetailPage(item)"> |
| | | <div class="price" v-if="item.price!=undefined"> |
| | | ¥<span>{{ $options.filters.goodsFormatPrice(item.price )[0] }} </span>.{{ |
| | | $options.filters.goodsFormatPrice(item.price )[1] |
| | | }} |
| | | </div> |
| | | </view> |
| | | <div class="promotion" @click="navigateToDetailPage(item)"> |
| | | <div v-if="item.salesModel == 'WHOLESALE'"> |
| | | <span>批</span> |
| | | </div> |
| | | <div v-for="(promotionItem,promotionIndex) in getPromotion(item)" :key="promotionIndex"> |
| | | <span v-if="promotionItem.indexOf('COUPON') != -1">劵</span> |
| | | <span v-if="promotionItem.indexOf('FULL_DISCOUNT') != -1">满减</span> |
| | | <span v-if="promotionItem.indexOf('SECKILL') != -1">秒杀</span> |
| | | </div> |
| | | </div> |
| | | <div style="overflow: hidden" @click="navigateToDetailPage(item)" class="count-config"> |
| | | <span style="float: left; font-size: 22rpx">已售 {{ item.buyCount || '0' }}</span> |
| | | <span style="float: right; font-size: 22rpx">{{ item.commentNum || '0' }}条评论</span> |
| | | </div> |
| | | <div style="overflow: hidden" @click="navigateToStoreDetailPage(item)" class="count-config"> |
| | | <div class="text-hidden" v-if="storeName"> |
| | | <u-tag style="margin-right: 10rpx" size="mini" mode="dark" v-if="item.selfOperated" |
| | | text="自营" type="error" /> |
| | | <span class="line1-store-name">{{ item.storeName }}</span> |
| | | <span class="to-store">进店<u-icon size="24" name="arrow-right" color="#666"></u-icon> |
| | | </span> |
| | | </div> |
| | | <span> |
| | | <u-icon name="arrow-right" color="#c5c5c5"></u-icon> |
| | | </span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | </div> |
| | | </div> |
| | | |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | import '@/components/uview-components/uview-ui'; |
| | | |
| | | import commonTpl from '@/pages/product/m-goods-list/common.vue' |
| | | export default { |
| | | data() { |
| | | return { |
| | | lightColor: this.$mainColor |
| | | } |
| | | }, |
| | | mixins: [commonTpl], |
| | | |
| | | props: { |
| | | // 遍历的数据 |
| | | res: { |
| | | type: Array, |
| | | default: () => { |
| | | return [] |
| | | } |
| | | }, |
| | | // 一行两列还是一行一列显示 |
| | | type: { |
| | | type: String, |
| | | default: 'twoColumns', |
| | | validator() { |
| | | return ['twoColumns', 'oneColumns'] |
| | | } |
| | | }, |
| | | storeName: { |
| | | type: Boolean, |
| | | default: true |
| | | }, |
| | | keyword: { |
| | | type: null, |
| | | default: '' |
| | | } |
| | | |
| | | }, |
| | | watch: { |
| | | keyword(val) { |
| | | if (val) { |
| | | this.lightSearchStr(val) |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | |
| | | // 高亮显示搜索内容 |
| | | lightSearchStr(keyword, str) { |
| | | if (!keyword) { |
| | | return str |
| | | } else { |
| | | let unicodes = ''; |
| | | for (let i of Array.from(keyword)) { |
| | | unicodes += this.unicode(i) + "|" |
| | | } |
| | | const rule = '(' + unicodes + ')' |
| | | const reg = new RegExp(rule, 'gi'); |
| | | return str ? str.replace(reg, matchValue => |
| | | `<span style="color:${this.lightColor}">${matchValue}</span>` |
| | | ) : '' |
| | | } |
| | | }, |
| | | // 转换为unicode |
| | | unicode(str) { |
| | | var value = ''; |
| | | for (var i = 0; i < str.length; i++) { |
| | | value += '\\u' + this.left_zero_4(parseInt(str.charCodeAt(i)).toString(16)); |
| | | } |
| | | return value; |
| | | }, |
| | | left_zero_4(str) { |
| | | if (str != null && str != '' && str != 'undefined') { |
| | | if (str.length == 2) { |
| | | return '00' + str; |
| | | } |
| | | } |
| | | return str; |
| | | }, |
| | | // 数据去重一下 只显示一次 减免 劵 什么的 |
| | | getPromotion(item) { |
| | | if (item ? item.promotionMap : item.promotionMap) { |
| | | const fieldList = item ? item.promotionMap : item.promotionMap |
| | | let array = []; |
| | | Object.keys(fieldList).forEach((child) => { |
| | | if (!array.includes(child.split("-")[0])) { |
| | | array.push(child.split("-")[0]); |
| | | } |
| | | }); |
| | | return array; |
| | | } |
| | | }, |
| | | // 跳转到商品详情 |
| | | navigateToDetailPage(item) { |
| | | uni.navigateTo({ |
| | | url: `/pages/product/goods?id=${item.id}&goodsId=${item.goodsId}`, |
| | | }); |
| | | }, |
| | | // 跳转地址 |
| | | navigateToStoreDetailPage(item) { |
| | | uni.navigateTo({ |
| | | url: `/pages/product/shopPage?id=${item.storeId}`, |
| | | }); |
| | | }, |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang='scss' scoped> |
| | | .goods-one-row{ |
| | | padding-bottom: 250rpx; |
| | | } |
| | | /* 商品列表 */ |
| | | .goods-list { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | margin: 10rpx 20rpx 284rpx; |
| | | width: 100%; |
| | | |
| | | >.goods-item { |
| | | background-color: #ffffff; |
| | | display: flex; |
| | | border-radius: 16rpx; |
| | | flex-direction: column; |
| | | width: calc(50% - 30rpx); |
| | | margin-bottom: 20rpx; |
| | | padding-bottom: 20rpx; |
| | | |
| | | &:nth-child(2n + 1) { |
| | | margin-right: 20rpx; |
| | | } |
| | | |
| | | |
| | | .image-wrapper { |
| | | width: 100%; |
| | | height: 330rpx; |
| | | border-radius: 16rpx 16rpx 0 0; |
| | | overflow: hidden; |
| | | padding: 0; |
| | | } |
| | | } |
| | | |
| | | .count-config, |
| | | .store-seller-name { |
| | | font-size: $font-sm; |
| | | } |
| | | |
| | | .text-hidden { |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | } |
| | | |
| | | |
| | | .goods-row { |
| | | background: #fff; |
| | | padding: 16rpx; |
| | | |
| | | >.goods-col { |
| | | display: flex; |
| | | |
| | | >.goods-img { |
| | | overflow: hidden; |
| | | flex: 4; |
| | | } |
| | | |
| | | >.goods-detail { |
| | | flex: 7; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .goods-detail { |
| | | margin: 0 20rpx; |
| | | |
| | | >.title { |
| | | font-size: $font-base; |
| | | color: $font-color-dark; |
| | | line-height: 1.5; |
| | | height: 86rpx; |
| | | padding: 10rpx 0 0; |
| | | display: -webkit-box; |
| | | -webkit-box-orient: vertical; |
| | | -webkit-line-clamp: 2; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .promotion { |
| | | margin-top: 4rpx; |
| | | display: flex; |
| | | |
| | | div { |
| | | span { |
| | | font-size: 24rpx; |
| | | color: $light-color; |
| | | margin-right: 10rpx; |
| | | padding: 0 4rpx; |
| | | border-radius: 2rpx; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .store-seller-name { |
| | | color: #666; |
| | | overflow: hidden; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .count-config { |
| | | padding: 5rpx 0; |
| | | color: #666; |
| | | display: flex; |
| | | font-size: 24rpx; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | >.price-box { |
| | | margin-top: 10rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding-right: 10rpx; |
| | | font-size: 24rpx; |
| | | color: $font-color-light; |
| | | |
| | | >.price { |
| | | font-size: 26rpx; |
| | | line-height: 1; |
| | | color: $main-color; |
| | | font-weight: bold; |
| | | |
| | | /deep/ span:nth-of-type(1) { |
| | | font-size: 38rpx; |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <div> |
| | | <div v-for="(item, index) in res" :key="index" class="goods-row" @click="navigateToDetailPage(item)"> |
| | | <div class="flex goods-col"> |
| | | <div class="goods-img"> |
| | | <u-image width="230rpx" mode="aspectFit" border-radius='16' height="230rpx" :src="item.goodsImage || item.thumbnail"> |
| | | <u-loading slot="loading"></u-loading> |
| | | </u-image> |
| | | </div> |
| | | <div class="goods-detail"> |
| | | <div class="title clamp3">{{ item.goodsName }}</div> |
| | | <div class='flex flex-a-c flex-j-sb'> |
| | | <view class="price-box"> |
| | | <!-- 秒杀 / 拼团 --> |
| | | <div class="price" v-if="!type && item.price!=undefined"> |
| | | ¥<span>{{ $options.filters.goodsFormatPrice(item.price )[0] }} </span>.{{ |
| | | $options.filters.goodsFormatPrice(item.price )[1] |
| | | }} |
| | | </div> |
| | | <!-- 砍价 --> |
| | | <div class="price" v-if="type && item.purchasePrice!=undefined"> |
| | | 最低: |
| | | ¥<span>{{ $options.filters.goodsFormatPrice(item.purchasePrice )[0] }} </span>.{{ |
| | | $options.filters.goodsFormatPrice(item.purchasePrice )[1] |
| | | }} |
| | | </div> |
| | | <!-- 兜底策略如果金额是0 --> |
| | | <div class="price" v-if="!item.price && !type"> |
| | | ¥<span>0 </span>.00 |
| | | </div> |
| | | </view> |
| | | <div> |
| | | <image class='buy' :src="buy"></image> |
| | | </div> |
| | | </div> |
| | | <div class='count-config' v-if="!type"> |
| | | <span>即将恢复{{ item.originalPrice}}元</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import '@/components/uview-components/uview-ui' |
| | | import commonTpl from '@/pages/product/m-goods-list/common.vue' |
| | | export default { |
| | | data() { |
| | | return { |
| | | lightColor: this.$mainColor, |
| | | buy: require('@/pages/subComponents/static/buy.png') |
| | | } |
| | | }, |
| | | mixins: [commonTpl], |
| | | props: { |
| | | // 遍历的数据 |
| | | res: { |
| | | type: Array, |
| | | default: () => { |
| | | return [] |
| | | } |
| | | }, |
| | | type:{ |
| | | type:null, |
| | | default:"" |
| | | } |
| | | }, |
| | | methods: { |
| | | // 跳转到商品详情 |
| | | navigateToDetailPage(item) { |
| | | if(this.type == 'kanJia'){ |
| | | uni.navigateTo({ |
| | | url: `/pages/promotion/bargain/detail?id=${item.id}`, |
| | | }); |
| | | return |
| | | } |
| | | uni.navigateTo({ |
| | | url: `/pages/product/goods?id=${item.skuId}&goodsId=${item.goodsId}`, |
| | | }); |
| | | }, |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang='scss' scoped> |
| | | .buy { |
| | | width: 152rpx; |
| | | height: 108rpx; |
| | | } |
| | | .flex-j-sb { |
| | | width: 100%; |
| | | } |
| | | .goods-row { |
| | | background: #fff; |
| | | padding: 16rpx; |
| | | >.goods-col { |
| | | display: flex; |
| | | >.goods-img { |
| | | overflow: hidden; |
| | | flex: 4; |
| | | } |
| | | >.goods-detail { |
| | | flex: 7; |
| | | } |
| | | } |
| | | } |
| | | .goods-detail { |
| | | margin: 0 20rpx; |
| | | >.title { |
| | | font-size: $font-base; |
| | | color: $font-color-dark; |
| | | line-height: 1.5; |
| | | height: 86rpx; |
| | | padding: 10rpx 0 0; |
| | | display: -webkit-box; |
| | | -webkit-box-orient: vertical; |
| | | -webkit-line-clamp: 2; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .promotion { |
| | | margin-top: 4rpx; |
| | | display: flex; |
| | | |
| | | div { |
| | | span { |
| | | font-size: 24rpx; |
| | | color: $light-color; |
| | | margin-right: 10rpx; |
| | | padding: 0 4rpx; |
| | | border-radius: 2rpx; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .count-config { |
| | | padding: 5rpx 0; |
| | | color: #666; |
| | | display: flex; |
| | | font-size: 24rpx; |
| | | letter-spacing:2rpx; |
| | | padding-left: 10rpx; |
| | | } |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | .price-box { |
| | | margin-top: 10rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding-right: 10rpx; |
| | | font-size: 24rpx; |
| | | color: $font-color-light; |
| | | |
| | | >.price { |
| | | font-size: 26rpx; |
| | | line-height: 1; |
| | | color: $main-color; |
| | | font-weight: bold; |
| | | |
| | | /deep/ span:nth-of-type(1) { |
| | | font-size: 48rpx; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <view class="shadow" :class="!show?'':'shadow-show'" :style="{backgroundColor:show?maskBg:'rgba(0,0,0,0)'}" @tap="tapMask"> |
| | | <view class="popups" :class="[theme]" :style="{top: popupsTop ,left: popupsLeft,flexDirection:direction}"> |
| | | <text :class="dynPlace" :style="{width:'0px',height:'0px'}" v-if="triangle"></text> |
| | | <view v-for="(item,index) in popData" :key="index" @tap.stop="tapItem(item)" class="itemChild view" :class="[direction=='row'?'solid-right':'solid-bottom',item.disabled?'disabledColor':'']"> |
| | | <u-icon size="35" :name="item.icon" v-if="item.icon"></u-icon><span class="title">{{item.title}}</span> |
| | | </view> |
| | | <slot></slot> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | import '@/components/uview-components/uview-ui'; |
| | | |
| | | export default { |
| | | |
| | | props: { |
| | | maskBg: { |
| | | type: String, |
| | | default: "rgba(0,0,0,0)", |
| | | }, |
| | | placement: { |
| | | type: String, |
| | | default: "default", //default top-start top-end bottom-start bottom-end |
| | | }, |
| | | direction: { |
| | | type: String, |
| | | default: "column", //column row |
| | | }, |
| | | x: { |
| | | type: Number, |
| | | default: 0, |
| | | }, |
| | | y: { |
| | | type: Number, |
| | | default: 0, |
| | | }, |
| | | value: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | popData: { |
| | | type: Array, |
| | | default: () => [], |
| | | }, |
| | | theme: { |
| | | type: String, |
| | | default: "light", //light dark |
| | | }, |
| | | dynamic: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | gap: { |
| | | type: Number, |
| | | default: 20, |
| | | }, |
| | | triangle: { |
| | | type: Boolean, |
| | | default: true, |
| | | }, |
| | | }, |
| | | data() { |
| | | return { |
| | | popupsTop: "0rpx", |
| | | popupsLeft: "0rpx", |
| | | show: false, |
| | | dynPlace: "", |
| | | }; |
| | | }, |
| | | mounted() { |
| | | this.popupsPosition(); |
| | | }, |
| | | methods: { |
| | | tapMask() { |
| | | this.$emit("input", !this.value); |
| | | }, |
| | | tapItem(item) { |
| | | if (item.disabled) return; |
| | | this.$emit("tapPopup", item); |
| | | this.$emit("input", !this.value); |
| | | }, |
| | | getStatusBar() { |
| | | let promise = new Promise((resolve, reject) => { |
| | | uni.getSystemInfo({ |
| | | success: function (e) { |
| | | let customBar; |
| | | // #ifdef H5 |
| | | |
| | | customBar = e.statusBarHeight + e.windowTop; |
| | | |
| | | // #endif |
| | | resolve(customBar); |
| | | }, |
| | | }); |
| | | }); |
| | | return promise; |
| | | }, |
| | | async popupsPosition() { |
| | | let statusBar = await this.getStatusBar(); |
| | | let promise = new Promise((resolve, reject) => { |
| | | let popupsDom = uni.createSelectorQuery().in(this).select(".popups"); |
| | | popupsDom |
| | | .fields( |
| | | { |
| | | size: true, |
| | | }, |
| | | (data) => { |
| | | let width = data.width; |
| | | let height = data.height; |
| | | |
| | | |
| | | |
| | | let y = this.dynamic |
| | | ? this.dynamicGetY(this.y, this.gap) |
| | | : this.transformRpx(this.y); |
| | | |
| | | let x = this.dynamic |
| | | ? this.dynamicGetX(this.x, this.gap) |
| | | : this.transformRpx(this.x); |
| | | |
| | | // #ifdef H5 |
| | | y = this.dynamic |
| | | ? this.y + statusBar |
| | | : this.transformRpx(this.y + statusBar); |
| | | // #endif |
| | | |
| | | this.dynPlace = |
| | | this.placement == "default" |
| | | ? this.getPlacement(x, y) |
| | | : this.placement; |
| | | |
| | | switch (this.dynPlace) { |
| | | case "top-start": |
| | | this.popupsTop = `${y + 9}rpx`; |
| | | this.popupsLeft = `${x - 15}rpx`; |
| | | break; |
| | | case "top-end": |
| | | this.popupsTop = `${y + 9}rpx`; |
| | | this.popupsLeft = `${x + 15 - width}rpx`; |
| | | break; |
| | | case "bottom-start": |
| | | this.popupsTop = `${y - 18 - height}rpx`; |
| | | this.popupsLeft = `${x - 15}rpx`; |
| | | break; |
| | | case "bottom-end": |
| | | this.popupsTop = `${y - 9 - height}rpx`; |
| | | this.popupsLeft = `${x + 15 - width}rpx`; |
| | | break; |
| | | } |
| | | resolve(); |
| | | } |
| | | ) |
| | | .exec(); |
| | | }); |
| | | return promise; |
| | | }, |
| | | getPlacement(x, y) { |
| | | let width = uni.getSystemInfoSync().windowWidth; |
| | | let height = uni.getSystemInfoSync().windowHeight; |
| | | if (x > width / 2 && y > height / 2) { |
| | | return "bottom-end"; |
| | | } else if (x < width / 2 && y < height / 2) { |
| | | return "top-start"; |
| | | } else if (x > width / 2 && y < height / 2) { |
| | | return "top-end"; |
| | | } else if (x < width / 2 && y > height / 2) { |
| | | return "bottom-start"; |
| | | } else if (x > width / 2) { |
| | | return "top-end"; |
| | | } else { |
| | | return "top-start"; |
| | | } |
| | | }, |
| | | dynamicGetY(y, gap) { |
| | | let height = uni.getSystemInfoSync().windowHeight; |
| | | y = y < gap ? gap : y; |
| | | y = height - y < gap ? height - gap : y; |
| | | |
| | | return y; |
| | | }, |
| | | dynamicGetX(x, gap) { |
| | | let width = uni.getSystemInfoSync().windowWidth; |
| | | x = x < gap ? gap : x; |
| | | x = width - x < gap ? width - gap : x; |
| | | return x; |
| | | }, |
| | | transformRpx(params) { |
| | | return (params * uni.getSystemInfoSync().screenWidth) / 375; |
| | | }, |
| | | }, |
| | | watch: { |
| | | value: { |
| | | immediate: true, |
| | | handler: async function (newVal, oldVal) { |
| | | if (newVal) await this.popupsPosition(); |
| | | this.show = newVal; |
| | | }, |
| | | }, |
| | | placement: { |
| | | immediate: true, |
| | | handler(newVal, oldVal) { |
| | | this.dynPlace = newVal; |
| | | }, |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .title { |
| | | margin-left: 20rpx; |
| | | } |
| | | .shadow { |
| | | position: fixed; |
| | | top: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | left: 0; |
| | | height: 100%; |
| | | z-index: 9999; |
| | | transition: background 0.3s ease-in-out; |
| | | visibility: hidden; |
| | | |
| | | &.shadow-show { |
| | | visibility: visible; |
| | | } |
| | | } |
| | | |
| | | .popups { |
| | | position: absolute; |
| | | padding: 20rpx; |
| | | border-radius: 5px; |
| | | display: flex; |
| | | .view { |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 15rpx 10rpx; |
| | | font-size: 25rpx; |
| | | } |
| | | .image { |
| | | display: inline-block; |
| | | vertical-align: middle; |
| | | width: 40rpx; |
| | | height: 40rpx; |
| | | margin-right: 20rpx; |
| | | } |
| | | } |
| | | .dark { |
| | | background-color: #4c4c4c; |
| | | color: #fff; |
| | | .top-start:after { |
| | | content: ""; |
| | | position: absolute; |
| | | top: -18rpx; |
| | | left: 10rpx; |
| | | border-width: 0 20rpx 20rpx; |
| | | border-style: solid; |
| | | border-color: transparent transparent #4c4c4c; |
| | | } |
| | | .top-end:after { |
| | | content: ""; |
| | | position: absolute; |
| | | top: -18rpx; |
| | | right: 10rpx; |
| | | border-width: 0 20rpx 20rpx; |
| | | border-style: solid; |
| | | border-color: transparent transparent #4c4c4c; |
| | | } |
| | | .bottom-start:after { |
| | | content: ""; |
| | | position: absolute; |
| | | bottom: -18rpx; |
| | | left: 10rpx; |
| | | border-width: 20rpx 20rpx 0; |
| | | border-style: solid; |
| | | border-color: #4c4c4c transparent transparent; |
| | | } |
| | | .bottom-end:after { |
| | | content: ""; |
| | | position: absolute; |
| | | bottom: -18rpx; |
| | | right: 10rpx; |
| | | border-width: 20rpx 20rpx 0; |
| | | border-style: solid; |
| | | border-color: #4c4c4c transparent transparent; |
| | | } |
| | | .disabledColor { |
| | | color: #c5c8ce; |
| | | } |
| | | } |
| | | .light { |
| | | color: #515a6e; |
| | | box-shadow: 0upx 0upx 30upx rgba(0, 0, 0, 0.2); |
| | | background: #fff; |
| | | .top-start:after { |
| | | content: ""; |
| | | position: absolute; |
| | | top: -18rpx; |
| | | left: 10rpx; |
| | | border-width: 0 20rpx 20rpx; |
| | | border-style: solid; |
| | | border-color: transparent transparent #fff; |
| | | } |
| | | .top-end:after { |
| | | content: ""; |
| | | position: absolute; |
| | | top: -18rpx; |
| | | right: 10rpx; |
| | | border-width: 0 20rpx 20rpx; |
| | | border-style: solid; |
| | | border-color: transparent transparent #fff; |
| | | } |
| | | .bottom-start:after { |
| | | content: ""; |
| | | position: absolute; |
| | | bottom: -18rpx; |
| | | left: 10rpx; |
| | | border-width: 20rpx 20rpx 0; |
| | | border-style: solid; |
| | | border-color: #fff transparent transparent; |
| | | } |
| | | .bottom-end:after { |
| | | content: ""; |
| | | position: absolute; |
| | | bottom: -18rpx; |
| | | right: 10rpx; |
| | | border-width: 20rpx 20rpx 0; |
| | | border-style: solid; |
| | | border-color: #fff transparent transparent; |
| | | } |
| | | .disabledColor { |
| | | color: #c5c8ce; |
| | | } |
| | | } |
| | | .solid-bottom { |
| | | border-bottom: 1px solid #f3f5f7; |
| | | } |
| | | .solid-right { |
| | | border-right: 1px solid #ccc; |
| | | } |
| | | .popups .itemChild:last-child { |
| | | border: none; |
| | | } |
| | | </style> |