From 408d93a7fed0403381400ce2fc028819bb203eec Mon Sep 17 00:00:00 2001 From: peng <peng.com> Date: 星期一, 21 七月 2025 09:51:42 +0800 Subject: [PATCH] 解决主包过大问题 --- pages/subComponents/m-goods-list/common.vue | 69 +++ pages/subComponents/m-goods-list/promotion.vue | 171 ++++++++ pages/product/goods.vue | 13 pages/subComponents/m-goods-list/base-list.vue | 277 +++++++++++++ pages/subComponents/m-goods-list/README.md | 11 pages.json | 16 pages/subComponents/popups/popups.vue | 346 ++++++++++++++++ pages/commodity-square/commoditySquare.vue | 4 pages/subComponents/m-goods-list/list.vue | 343 ++++++++++++++++ 9 files changed, 1,240 insertions(+), 10 deletions(-) diff --git a/pages.json b/pages.json index 06eec49..93752ba 100644 --- a/pages.json +++ b/pages.json @@ -1026,7 +1026,8 @@ "componentPlaceholder": { "u-icon": "view", "u-navbar": "view", - "u-popup": "view" + "u-popup": "view", + "popups":"view" } } }, @@ -1714,6 +1715,19 @@ { "navigationBarTitleText" : "鍒嗗寘鍗犱綅" } + },{ + "path" : "popups/popups", + "style" : + { + "componentPlaceholder": { + "u-modal": "view", + "u-tabs": "view", + "u-image": "view", + "u-search": "view", + "u-icon": "view", + "u-loadmore": "view" + } + } } ] }, diff --git a/pages/commodity-square/commoditySquare.vue b/pages/commodity-square/commoditySquare.vue index 7bbfbd0..68da6c9 100644 --- a/pages/commodity-square/commoditySquare.vue +++ b/pages/commodity-square/commoditySquare.vue @@ -16,8 +16,8 @@ </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)" diff --git a/pages/product/goods.vue b/pages/product/goods.vue index b905084..c315288 100644 --- a/pages/product/goods.vue +++ b/pages/product/goods.vue @@ -184,24 +184,24 @@ <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> @@ -295,14 +295,14 @@ 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 { @@ -318,7 +318,6 @@ PromotionAssembleListLayout, PromotionCoupon, GoodsIntro, - GoodsRecommend, storeLayout, Evaluation, GoodsSwiper, diff --git a/pages/subComponents/m-goods-list/README.md b/pages/subComponents/m-goods-list/README.md new file mode 100644 index 0000000..bade838 --- /dev/null +++ b/pages/subComponents/m-goods-list/README.md @@ -0,0 +1,11 @@ +## 鍟嗗搧鍒楄〃灞曠ず + +### OBJECT 鍙傛暟璇存槑 + +| 灞炴�� | 璇存槑 | 绫诲瀷 | 蹇呭~ | +| ----------- | ---------------------------------------------------------- | ------- | ---- | +| `res` | 鏄剧ず鏁版嵁 | Array | 鏄� | +| `type` | 鍟嗗搧灞曠ず绫诲瀷 oneColumns twoColumns 锛岄粯璁ゅ睍绀轰竴琛屼袱鍒楀晢鍝� | String | 鍚� | +| `storeName` | 鏄惁灞曠ず搴楅摵鍚嶇О锛岄粯璁ゅ睍绀� | Boolean | 鍚� | +| `keywords` | 楂樹寒灞曠ず鎼滅储鍐呭 | String | 鍚� | + diff --git a/pages/subComponents/m-goods-list/base-list.vue b/pages/subComponents/m-goods-list/base-list.vue new file mode 100644 index 0000000..62d57a4 --- /dev/null +++ b/pages/subComponents/m-goods-list/base-list.vue @@ -0,0 +1,277 @@ +<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> diff --git a/pages/subComponents/m-goods-list/common.vue b/pages/subComponents/m-goods-list/common.vue new file mode 100644 index 0000000..c4cdc56 --- /dev/null +++ b/pages/subComponents/m-goods-list/common.vue @@ -0,0 +1,69 @@ +<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>` + ) : '' + } + }, + // 杞崲涓簎nicode + 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> diff --git a/pages/subComponents/m-goods-list/list.vue b/pages/subComponents/m-goods-list/list.vue new file mode 100644 index 0000000..fa54ff5 --- /dev/null +++ b/pages/subComponents/m-goods-list/list.vue @@ -0,0 +1,343 @@ +<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>` + ) : '' + } + }, + // 杞崲涓簎nicode + 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> diff --git a/pages/subComponents/m-goods-list/promotion.vue b/pages/subComponents/m-goods-list/promotion.vue new file mode 100644 index 0000000..90bc250 --- /dev/null +++ b/pages/subComponents/m-goods-list/promotion.vue @@ -0,0 +1,171 @@ +<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> diff --git a/pages/subComponents/popups/popups.vue b/pages/subComponents/popups/popups.vue new file mode 100644 index 0000000..ce373f9 --- /dev/null +++ b/pages/subComponents/popups/popups.vue @@ -0,0 +1,346 @@ +<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> -- Gitblit v1.8.0