通过微信开发者工具 商城模板 创建新小程序
This commit is contained in:
		
							
								
								
									
										59
									
								
								mini-program/pages/cart/components/cart-bar/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								mini-program/pages/cart/components/cart-bar/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
			
		||||
Component({
 | 
			
		||||
  options: {
 | 
			
		||||
    addGlobalClass: true,
 | 
			
		||||
  },
 | 
			
		||||
  /**
 | 
			
		||||
   * 组件的属性列表
 | 
			
		||||
   */
 | 
			
		||||
  properties: {
 | 
			
		||||
    isAllSelected: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      value: false,
 | 
			
		||||
    },
 | 
			
		||||
    totalAmount: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      value: 1,
 | 
			
		||||
    },
 | 
			
		||||
    totalGoodsNum: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      value: 0,
 | 
			
		||||
      observer(num) {
 | 
			
		||||
        const isDisabled = num == 0;
 | 
			
		||||
        setTimeout(() => {
 | 
			
		||||
          this.setData({
 | 
			
		||||
            isDisabled,
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    totalDiscountAmount: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      value: 0,
 | 
			
		||||
    },
 | 
			
		||||
    bottomHeight: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      value: 100,
 | 
			
		||||
    },
 | 
			
		||||
    fixed: Boolean,
 | 
			
		||||
  },
 | 
			
		||||
  data: {
 | 
			
		||||
    isDisabled: false,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    handleSelectAll() {
 | 
			
		||||
      const { isAllSelected } = this.data;
 | 
			
		||||
      this.setData({
 | 
			
		||||
        isAllSelected: !isAllSelected,
 | 
			
		||||
      });
 | 
			
		||||
      this.triggerEvent('handleSelectAll', {
 | 
			
		||||
        isAllSelected: isAllSelected,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    handleToSettle() {
 | 
			
		||||
      if (this.data.isDisabled) return;
 | 
			
		||||
      this.triggerEvent('handleToSettle');
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										7
									
								
								mini-program/pages/cart/components/cart-bar/index.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								mini-program/pages/cart/components/cart-bar/index.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "price": "/components/price/index",
 | 
			
		||||
    "t-icon": "tdesign-miniprogram/icon/icon"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								mini-program/pages/cart/components/cart-bar/index.wxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								mini-program/pages/cart/components/cart-bar/index.wxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
<view class="cart-bar__placeholder" wx:if="{{fixed}}" />
 | 
			
		||||
<view class="cart-bar {{fixed ? 'cart-bar--fixed' : ''}} flex flex-v-center" style="bottom: {{fixed ? 'calc(' + bottomHeight + 'rpx + env(safe-area-inset-bottom))' : ''}};">
 | 
			
		||||
	<t-icon
 | 
			
		||||
	 size="40rpx"
 | 
			
		||||
	 color="{{isAllSelected ? '#FA4126' : '#BBBBBB'}}"
 | 
			
		||||
	 name="{{isAllSelected ? 'check-circle-filled' : 'circle'}}"
 | 
			
		||||
	 class="cart-bar__check"
 | 
			
		||||
	 catchtap="handleSelectAll"
 | 
			
		||||
	/>
 | 
			
		||||
	<text>全选</text>
 | 
			
		||||
	<view class="cart-bar__total flex1">
 | 
			
		||||
		<view>
 | 
			
		||||
			<text class="cart-bar__total--bold text-padding-right">总计</text>
 | 
			
		||||
			<price
 | 
			
		||||
			 price="{{totalAmount || '0'}}"
 | 
			
		||||
			 fill="{{false}}"
 | 
			
		||||
			 decimalSmaller
 | 
			
		||||
			 class="cart-bar__total--bold cart-bar__total--price"
 | 
			
		||||
			/>
 | 
			
		||||
			<text class="cart-bar__total--normal">(不含运费)</text>
 | 
			
		||||
		</view>
 | 
			
		||||
		<view wx:if="{{totalDiscountAmount}}">
 | 
			
		||||
			<text class="cart-bar__total--normal text-padding-right">已优惠</text>
 | 
			
		||||
			<price class="cart-bar__total--normal" price="{{totalDiscountAmount || '0'}}" fill="{{false}}" />
 | 
			
		||||
		</view>
 | 
			
		||||
	</view>
 | 
			
		||||
	<view catchtap="handleToSettle" class="{{!isDisabled ? '' : 'disabled-btn'}} account-btn" hover-class="{{!isDisabled ? '' : 'hover-btn'}}">
 | 
			
		||||
		去结算({{totalGoodsNum}})
 | 
			
		||||
	</view>
 | 
			
		||||
</view>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										80
									
								
								mini-program/pages/cart/components/cart-bar/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								mini-program/pages/cart/components/cart-bar/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,80 @@
 | 
			
		||||
.cart-bar__placeholder {
 | 
			
		||||
  height: 100rpx;
 | 
			
		||||
}
 | 
			
		||||
.flex {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
.flex-v-center {
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
.flex1 {
 | 
			
		||||
  flex: 1;
 | 
			
		||||
}
 | 
			
		||||
.algin-bottom {
 | 
			
		||||
  text-align: end;
 | 
			
		||||
}
 | 
			
		||||
.cart-bar--fixed {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  z-index: 99;
 | 
			
		||||
  bottom: calc(100rpx + env(safe-area-inset-bottom));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.cart-bar {
 | 
			
		||||
  height: 112rpx;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  border-top: 1rpx solid #e5e5e5;
 | 
			
		||||
  padding: 16rpx 32rpx;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  line-height: 36rpx;
 | 
			
		||||
  color: #333;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.cart-bar .cart-bar__check {
 | 
			
		||||
  margin-right: 12rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.cart-bar .cart-bar__total {
 | 
			
		||||
  margin-left: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.cart-bar .account-btn {
 | 
			
		||||
  width: 192rpx;
 | 
			
		||||
  height: 80rpx;
 | 
			
		||||
  border-radius: 40rpx;
 | 
			
		||||
  background-color: #fa4126;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  line-height: 80rpx;
 | 
			
		||||
  color: #ffffff;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
.cart-bar .disabled-btn {
 | 
			
		||||
  background-color: #cccccc !important;
 | 
			
		||||
}
 | 
			
		||||
.cart-bar .hover-btn {
 | 
			
		||||
  opacity: 0.5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.cart-bar__total .cart-bar__total--bold {
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  line-height: 40rpx;
 | 
			
		||||
  color: #333;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
.cart-bar__total .cart-bar__total--normal {
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  line-height: 32rpx;
 | 
			
		||||
  color: #999;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.cart-bar__total .cart-bar__total--price {
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.text-padding-right {
 | 
			
		||||
  padding-right: 4rpx;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								mini-program/pages/cart/components/cart-empty/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								mini-program/pages/cart/components/cart-empty/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
Component({
 | 
			
		||||
  properties: {
 | 
			
		||||
    imgUrl: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value:
 | 
			
		||||
        'https://cdn-we-retail.ym.tencent.com/miniapp/template/empty-cart.png',
 | 
			
		||||
    },
 | 
			
		||||
    tip: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '购物车是空的',
 | 
			
		||||
    },
 | 
			
		||||
    btnText: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '去首页',
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  data: {},
 | 
			
		||||
  methods: {
 | 
			
		||||
    handleClick() {
 | 
			
		||||
      this.triggerEvent('handleClick');
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										6
									
								
								mini-program/pages/cart/components/cart-empty/index.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								mini-program/pages/cart/components/cart-empty/index.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "t-image": "/components/webp-image/index"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								mini-program/pages/cart/components/cart-empty/index.wxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								mini-program/pages/cart/components/cart-empty/index.wxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
<view class="cart-empty">
 | 
			
		||||
	<t-image t-class="cart-img" src="{{imgUrl}}" />
 | 
			
		||||
	<view class="tip">{{tip}}</view>
 | 
			
		||||
	<view class="btn" bind:tap="handleClick">{{btnText}}</view>
 | 
			
		||||
</view>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										33
									
								
								mini-program/pages/cart/components/cart-empty/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								mini-program/pages/cart/components/cart-empty/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
.cart-empty {
 | 
			
		||||
  padding: 64rpx 0rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  height: calc(100vh - 100rpx);
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
}
 | 
			
		||||
.cart-empty .cart-img {
 | 
			
		||||
  width: 160rpx;
 | 
			
		||||
  height: 160rpx;
 | 
			
		||||
  margin-bottom: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.cart-empty .tip {
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  line-height: 40rpx;
 | 
			
		||||
  color: #999;
 | 
			
		||||
  margin-bottom: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
.cart-empty .btn {
 | 
			
		||||
  width: 240rpx;
 | 
			
		||||
  height: 72rpx;
 | 
			
		||||
  border-radius: 36rpx;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  line-height: 72rpx;
 | 
			
		||||
  border: 2rpx solid #fa4126;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										166
									
								
								mini-program/pages/cart/components/cart-group/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								mini-program/pages/cart/components/cart-group/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,166 @@
 | 
			
		||||
import Toast from 'tdesign-miniprogram/toast/index';
 | 
			
		||||
 | 
			
		||||
const shortageImg =
 | 
			
		||||
  'https://cdn-we-retail.ym.tencent.com/miniapp/cart/shortage.png';
 | 
			
		||||
 | 
			
		||||
Component({
 | 
			
		||||
  isSpecsTap: false, // 标记本次点击事件是否因为点击specs触发(由于底层goods-card组件没有catch specs点击事件,只能在此处加状态来避免点击specs时触发跳转商品详情)
 | 
			
		||||
  externalClasses: ['wr-class'],
 | 
			
		||||
  properties: {
 | 
			
		||||
    storeGoods: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      observer(storeGoods) {
 | 
			
		||||
        for (const store of storeGoods) {
 | 
			
		||||
          for (const activity of store.promotionGoodsList) {
 | 
			
		||||
            for (const goods of activity.goodsPromotionList) {
 | 
			
		||||
              goods.specs = goods.specInfo.map((item) => item.specValue); // 目前仅展示商品已选规格的值
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          for (const goods of store.shortageGoodsList) {
 | 
			
		||||
            goods.specs = goods.specInfo.map((item) => item.specValue); // 目前仅展示商品已选规格的值
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.setData({ _storeGoods: storeGoods });
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    invalidGoodItems: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      observer(invalidGoodItems) {
 | 
			
		||||
        invalidGoodItems.forEach((goods) => {
 | 
			
		||||
          goods.specs = goods.specInfo.map((item) => item.specValue); // 目前仅展示商品已选规格的值
 | 
			
		||||
        });
 | 
			
		||||
        this.setData({ _invalidGoodItems: invalidGoodItems });
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    thumbWidth: { type: null },
 | 
			
		||||
    thumbHeight: { type: null },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  data: {
 | 
			
		||||
    shortageImg,
 | 
			
		||||
    isShowSpecs: false,
 | 
			
		||||
    currentGoods: {},
 | 
			
		||||
    isShowToggle: false,
 | 
			
		||||
    _storeGoods: [],
 | 
			
		||||
    _invalidGoodItems: [],
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    // 删除商品
 | 
			
		||||
    deleteGoods(e) {
 | 
			
		||||
      const { goods } = e.currentTarget.dataset;
 | 
			
		||||
      this.triggerEvent('delete', { goods });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 清空失效商品
 | 
			
		||||
    clearInvalidGoods() {
 | 
			
		||||
      this.triggerEvent('clearinvalidgoods');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 选中商品
 | 
			
		||||
    selectGoods(e) {
 | 
			
		||||
      const { goods } = e.currentTarget.dataset;
 | 
			
		||||
      this.triggerEvent('selectgoods', {
 | 
			
		||||
        goods,
 | 
			
		||||
        isSelected: !goods.isSelected,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    changeQuantity(num, goods) {
 | 
			
		||||
      this.triggerEvent('changequantity', {
 | 
			
		||||
        goods,
 | 
			
		||||
        quantity: num,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    changeStepper(e) {
 | 
			
		||||
      const { value } = e.detail;
 | 
			
		||||
      const { goods } = e.currentTarget.dataset;
 | 
			
		||||
      let num = value;
 | 
			
		||||
      if (value > goods.stack) {
 | 
			
		||||
        num = goods.stack;
 | 
			
		||||
      }
 | 
			
		||||
      this.changeQuantity(num, goods);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    input(e) {
 | 
			
		||||
      const { value } = e.detail;
 | 
			
		||||
      const { goods } = e.currentTarget.dataset;
 | 
			
		||||
      const num = value;
 | 
			
		||||
      this.changeQuantity(num, goods);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    overlimit(e) {
 | 
			
		||||
      const text =
 | 
			
		||||
        e.detail.type === 'minus'
 | 
			
		||||
          ? '该商品数量不能减少了哦'
 | 
			
		||||
          : '同一商品最多购买999件';
 | 
			
		||||
      Toast({
 | 
			
		||||
        context: this,
 | 
			
		||||
        selector: '#t-toast',
 | 
			
		||||
        message: text,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 去凑单/再逛逛
 | 
			
		||||
    gotoBuyMore(e) {
 | 
			
		||||
      const { promotion, storeId = '' } = e.currentTarget.dataset;
 | 
			
		||||
      this.triggerEvent('gocollect', { promotion, storeId });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 选中门店
 | 
			
		||||
    selectStore(e) {
 | 
			
		||||
      const { storeIndex } = e.currentTarget.dataset;
 | 
			
		||||
      const store = this.data.storeGoods[storeIndex];
 | 
			
		||||
      const isSelected = !store.isSelected;
 | 
			
		||||
      if (store.storeStockShortage && isSelected) {
 | 
			
		||||
        Toast({
 | 
			
		||||
          context: this,
 | 
			
		||||
          selector: '#t-toast',
 | 
			
		||||
          message: '部分商品库存不足',
 | 
			
		||||
        });
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      this.triggerEvent('selectstore', {
 | 
			
		||||
        store,
 | 
			
		||||
        isSelected,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 展开/收起切换
 | 
			
		||||
    showToggle() {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        isShowToggle: !this.data.isShowToggle,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 展示规格popup
 | 
			
		||||
    specsTap(e) {
 | 
			
		||||
      this.isSpecsTap = true;
 | 
			
		||||
      const { goods } = e.currentTarget.dataset;
 | 
			
		||||
      this.setData({
 | 
			
		||||
        isShowSpecs: true,
 | 
			
		||||
        currentGoods: goods,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hideSpecsPopup() {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        isShowSpecs: false,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    goGoodsDetail(e) {
 | 
			
		||||
      if (this.isSpecsTap) {
 | 
			
		||||
        this.isSpecsTap = false;
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      const { goods } = e.currentTarget.dataset;
 | 
			
		||||
      this.triggerEvent('goodsclick', { goods });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    gotoCoupons() {
 | 
			
		||||
      wx.navigateTo({ url: '/pages/coupon/coupon-list/index' });
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										11
									
								
								mini-program/pages/cart/components/cart-group/index.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								mini-program/pages/cart/components/cart-group/index.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "t-toast": "tdesign-miniprogram/toast/toast",
 | 
			
		||||
    "t-icon": "tdesign-miniprogram/icon/icon",
 | 
			
		||||
    "t-stepper": "tdesign-miniprogram/stepper/stepper",
 | 
			
		||||
    "swipeout": "/components/swipeout/index",
 | 
			
		||||
    "goods-card": "../../components/goods-card/index",
 | 
			
		||||
    "specs-popup": "../../components/specs-popup/index"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										152
									
								
								mini-program/pages/cart/components/cart-group/index.wxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								mini-program/pages/cart/components/cart-group/index.wxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,152 @@
 | 
			
		||||
<wxs src="./index.wxs" module="handlePromotion" />
 | 
			
		||||
<wxs src="./utils.wxs" module="utils" />
 | 
			
		||||
 | 
			
		||||
<view class="cart-group">
 | 
			
		||||
  <view class="goods-wrap" wx:for="{{_storeGoods}}" wx:for-item="store" wx:for-index="si" wx:key="storeId">
 | 
			
		||||
    <view class="cart-store">
 | 
			
		||||
      <t-icon
 | 
			
		||||
        size="40rpx"
 | 
			
		||||
        color="{{store.isSelected ? '#FA4126' : '#BBBBBB'}}"
 | 
			
		||||
        name="{{store.isSelected ? 'check-circle-filled' : 'circle'}}"
 | 
			
		||||
        class="cart-store__check"
 | 
			
		||||
        bindtap="selectStore"
 | 
			
		||||
        data-store-index="{{si}}"
 | 
			
		||||
      />
 | 
			
		||||
      <view class="cart-store__content">
 | 
			
		||||
        <view class="store-title">
 | 
			
		||||
          <t-icon prefix="wr" size="40rpx" color="#333333" name="store" />
 | 
			
		||||
          <view class="store-name">{{store.storeName}}</view>
 | 
			
		||||
        </view>
 | 
			
		||||
        <view class="get-coupon" catch:tap="gotoCoupons">优惠券</view>
 | 
			
		||||
      </view>
 | 
			
		||||
    </view>
 | 
			
		||||
    <block wx:for="{{store.promotionGoodsList}}" wx:for-item="promotion" wx:for-index="promoindex" wx:key="promoindex">
 | 
			
		||||
      <view
 | 
			
		||||
        class="promotion-wrap"
 | 
			
		||||
        wx:if="{{handlePromotion.hasPromotion(promotion.promotionCode)}}"
 | 
			
		||||
        bindtap="gotoBuyMore"
 | 
			
		||||
        data-promotion="{{promotion}}"
 | 
			
		||||
        data-store-id="{{store.storeId}}"
 | 
			
		||||
      >
 | 
			
		||||
        <view class="promotion-title">
 | 
			
		||||
          <view class="promotion-icon">{{promotion.tag}}</view>
 | 
			
		||||
          <view class="promotion-text">{{promotion.description}}</view>
 | 
			
		||||
        </view>
 | 
			
		||||
        <view class="promotion-action action-btn" hover-class="action-btn--active">
 | 
			
		||||
          <view class="promotion-action-label"> {{promotion.isNeedAddOnShop == 1 ? '去凑单' : '再逛逛'}} </view>
 | 
			
		||||
          <t-icon name="chevron-right" size="32rpx" color="#BBBBBB" />
 | 
			
		||||
        </view>
 | 
			
		||||
      </view>
 | 
			
		||||
      <view
 | 
			
		||||
        class="goods-item"
 | 
			
		||||
        wx:for="{{promotion.goodsPromotionList}}"
 | 
			
		||||
        wx:for-item="goods"
 | 
			
		||||
        wx:for-index="gi"
 | 
			
		||||
        wx:key="extKey"
 | 
			
		||||
      >
 | 
			
		||||
        <swipeout right-width="{{ 72 }}">
 | 
			
		||||
          <view class="goods-item-info">
 | 
			
		||||
            <view class="check-wrap" catchtap="selectGoods" data-goods="{{goods}}">
 | 
			
		||||
              <t-icon
 | 
			
		||||
                size="40rpx"
 | 
			
		||||
                color="{{goods.isSelected ? '#FA4126' : '#BBBBBB'}}"
 | 
			
		||||
                name="{{goods.isSelected ? 'check-circle-filled' : 'circle'}}"
 | 
			
		||||
                class="check"
 | 
			
		||||
              />
 | 
			
		||||
            </view>
 | 
			
		||||
            <view class="goods-sku-info">
 | 
			
		||||
              <goods-card
 | 
			
		||||
                layout="horizontal-wrap"
 | 
			
		||||
                thumb-width="{{thumbWidth}}"
 | 
			
		||||
                thumb-height="{{thumbHeight}}"
 | 
			
		||||
                centered="{{true}}"
 | 
			
		||||
                data="{{goods}}"
 | 
			
		||||
                data-goods="{{goods}}"
 | 
			
		||||
                catchspecs="specsTap"
 | 
			
		||||
                catchclick="goGoodsDetail"
 | 
			
		||||
              >
 | 
			
		||||
                <view slot="thumb-cover" class="stock-mask" wx:if="{{goods.shortageStock || goods.stockQuantity <= 3}}">
 | 
			
		||||
                  仅剩{{goods.stockQuantity}}件
 | 
			
		||||
                </view>
 | 
			
		||||
                <view slot="append-body" class="goods-stepper">
 | 
			
		||||
                  <view class="stepper-tip" wx:if="{{goods.shortageStock}}">库存不足</view>
 | 
			
		||||
                  <t-stepper
 | 
			
		||||
                    classname="stepper-info"
 | 
			
		||||
                    value="{{goods.quantity}}"
 | 
			
		||||
                    min="{{1}}"
 | 
			
		||||
                    max="{{999}}"
 | 
			
		||||
                    data-goods="{{goods}}"
 | 
			
		||||
                    data-gi="{{gi}}"
 | 
			
		||||
                    data-si="{{si}}"
 | 
			
		||||
                    catchchange="changeStepper"
 | 
			
		||||
                    catchblur="input"
 | 
			
		||||
                    catchoverlimit="overlimit"
 | 
			
		||||
                    theme="filled"
 | 
			
		||||
                  />
 | 
			
		||||
                </view>
 | 
			
		||||
              </goods-card>
 | 
			
		||||
            </view>
 | 
			
		||||
          </view>
 | 
			
		||||
          <view slot="right" class="swiper-right-del" bindtap="deleteGoods" data-goods="{{goods}}"> 删除 </view>
 | 
			
		||||
        </swipeout>
 | 
			
		||||
      </view>
 | 
			
		||||
      <view
 | 
			
		||||
        class="promotion-line-wrap"
 | 
			
		||||
        wx:if="{{handlePromotion.hasPromotion(promotion.promotionCode) && promoindex != (store.promotionGoodsList.length - 2)}}"
 | 
			
		||||
      >
 | 
			
		||||
        <view class="promotion-line" />
 | 
			
		||||
      </view>
 | 
			
		||||
    </block>
 | 
			
		||||
    <block wx:if="{{store.shortageGoodsList.length>0}}">
 | 
			
		||||
      <view
 | 
			
		||||
        class="goods-item"
 | 
			
		||||
        wx:for="{{store.shortageGoodsList}}"
 | 
			
		||||
        wx:for-item="goods"
 | 
			
		||||
        wx:for-index="gi"
 | 
			
		||||
        wx:key="extKey"
 | 
			
		||||
      >
 | 
			
		||||
        <swipeout right-width="{{ 72 }}">
 | 
			
		||||
          <view class="goods-item-info">
 | 
			
		||||
            <view class="check-wrap">
 | 
			
		||||
              <view class="unCheck-icon" />
 | 
			
		||||
            </view>
 | 
			
		||||
            <view class="goods-sku-info">
 | 
			
		||||
              <goods-card
 | 
			
		||||
                layout="horizontal-wrap"
 | 
			
		||||
                thumb-width="{{thumbWidth}}"
 | 
			
		||||
                thumb-height="{{thumbHeight}}"
 | 
			
		||||
                centered="{{true}}"
 | 
			
		||||
                data="{{goods}}"
 | 
			
		||||
                data-goods="{{goods}}"
 | 
			
		||||
                catchspecs="specsTap"
 | 
			
		||||
                catchclick="goGoodsDetail"
 | 
			
		||||
              >
 | 
			
		||||
                <view slot="thumb-cover" class="no-storage-mask" wx:if="{{goods.stockQuantity <=0}}">
 | 
			
		||||
                  <view class="no-storage-content">无货</view>
 | 
			
		||||
                </view>
 | 
			
		||||
              </goods-card>
 | 
			
		||||
            </view>
 | 
			
		||||
          </view>
 | 
			
		||||
          <view slot="right" class="swiper-right-del" bindtap="deleteGoods" data-goods="{{goods}}"> 删除 </view>
 | 
			
		||||
        </swipeout>
 | 
			
		||||
      </view>
 | 
			
		||||
      <view
 | 
			
		||||
        class="promotion-line-wrap"
 | 
			
		||||
        wx:if="{{handlePromotion.hasPromotion(promotion.promotionCode) && promoindex != (store.promotionGoodsList.length - 2)}}"
 | 
			
		||||
      >
 | 
			
		||||
        <view class="promotion-line" />
 | 
			
		||||
      </view>
 | 
			
		||||
    </block>
 | 
			
		||||
  </view>
 | 
			
		||||
</view>
 | 
			
		||||
<specs-popup
 | 
			
		||||
  show="{{isShowSpecs}}"
 | 
			
		||||
  title="{{currentGoods.title || ''}}"
 | 
			
		||||
  price="{{currentGoods.price || ''}}"
 | 
			
		||||
  thumb="{{utils.imgCut(currentGoods.thumb, 180, 180)}}"
 | 
			
		||||
  specs="{{currentGoods.specs || []}}"
 | 
			
		||||
  zIndex="{{999}}"
 | 
			
		||||
  bindclose="hideSpecsPopup"
 | 
			
		||||
/>
 | 
			
		||||
 | 
			
		||||
<t-toast id="t-toast" />
 | 
			
		||||
							
								
								
									
										5
									
								
								mini-program/pages/cart/components/cart-group/index.wxs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								mini-program/pages/cart/components/cart-group/index.wxs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
var hasPromotion = function (code) {
 | 
			
		||||
  return code && code !== 'EMPTY_PROMOTION';
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module.exports.hasPromotion = hasPromotion;
 | 
			
		||||
							
								
								
									
										335
									
								
								mini-program/pages/cart/components/cart-group/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										335
									
								
								mini-program/pages/cart/components/cart-group/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,335 @@
 | 
			
		||||
.cart-group {
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .goods-wrap {
 | 
			
		||||
  margin-top: 40rpx;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .goods-wrap:first-of-type {
 | 
			
		||||
  margin-top: 0;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .cart-store {
 | 
			
		||||
  height: 96rpx;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  padding: 0rpx 24rpx 0rpx 36rpx;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .cart-store .cart-store__check {
 | 
			
		||||
  padding: 28rpx 32rpx 28rpx 0rpx;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .cart-store__content {
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  flex: auto;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .cart-store__content .store-title {
 | 
			
		||||
  flex: auto;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  line-height: 40rpx;
 | 
			
		||||
  color: #333333;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.cart-group .cart-store__content .store-title .wr-store {
 | 
			
		||||
  font-size: 32rpx;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .cart-store__content .store-title .store-name {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
  text-overflow: ellipsis;
 | 
			
		||||
  margin-left: 12rpx;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .cart-store__content .get-coupon {
 | 
			
		||||
  width: 112rpx;
 | 
			
		||||
  height: 40rpx;
 | 
			
		||||
  border-radius: 20rpx;
 | 
			
		||||
  background-color: #ffecf9;
 | 
			
		||||
  line-height: 40rpx;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.cart-group .promotion-wrap {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  padding: 0rpx 24rpx 32rpx 36rpx;
 | 
			
		||||
  background-color: #ffffff;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  line-height: 36rpx;
 | 
			
		||||
  color: #222427;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .promotion-wrap .promotion-title {
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  flex: auto;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  margin-right: 20rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .promotion-wrap .promotion-title .promotion-icon {
 | 
			
		||||
  flex: none;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  padding: 0 8rpx;
 | 
			
		||||
  color: #ffffff;
 | 
			
		||||
  background: #fa4126;
 | 
			
		||||
  font-size: 20rpx;
 | 
			
		||||
  height: 32rpx;
 | 
			
		||||
  line-height: 32rpx;
 | 
			
		||||
  margin-right: 16rpx;
 | 
			
		||||
  border-radius: 16rpx;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .promotion-wrap .promotion-title .promotion-text {
 | 
			
		||||
  flex: auto;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  text-overflow: ellipsis;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .promotion-wrap .promotion-action {
 | 
			
		||||
  flex: none;
 | 
			
		||||
  color: #333333;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .promotion-line-wrap {
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  height: 2rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: flex-end;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .promotion-line-wrap .promotion-line {
 | 
			
		||||
  width: 684rpx;
 | 
			
		||||
  height: 2rpx;
 | 
			
		||||
  background-color: #e6e6e6;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .goods-item-info {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  align-items: flex-start;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .goods-item-info .check-wrap {
 | 
			
		||||
  margin-top: 56rpx;
 | 
			
		||||
  padding: 20rpx 28rpx 20rpx 36rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.cart-group .goods-item-info .check-wrap .unCheck-icon {
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  width: 36rpx;
 | 
			
		||||
  height: 36rpx;
 | 
			
		||||
  border-radius: 20rpx;
 | 
			
		||||
  background: #f5f5f5;
 | 
			
		||||
  border: 2rpx solid #bbbbbb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.cart-group .goods-item-info .goods-sku-info {
 | 
			
		||||
  padding: 0rpx 32rpx 40rpx 0;
 | 
			
		||||
  flex-grow: 1;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .goods-item-info .goods-sku-info .stock-mask {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  bottom: 0rpx;
 | 
			
		||||
  background-color: rgba(0, 0, 0, 0.5);
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 40rpx;
 | 
			
		||||
  line-height: 40rpx;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .goods-item-info .goods-sku-info .goods-stepper {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  bottom: 8rpx;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .goods-item-info .goods-sku-info .goods-stepper .stepper-tip {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: -36rpx;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  height: 28rpx;
 | 
			
		||||
  color: #ff2525;
 | 
			
		||||
  font-size: 20rpx;
 | 
			
		||||
  line-height: 28rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.cart-group .shortage-line {
 | 
			
		||||
  width: 662rpx;
 | 
			
		||||
  height: 2rpx;
 | 
			
		||||
  background-color: #e6e6e6;
 | 
			
		||||
  margin: 0 auto;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .shortage-goods-wrap {
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
}
 | 
			
		||||
.cart-group .shortage-goods-wrap .shortage-tip-title {
 | 
			
		||||
  height: 72rpx;
 | 
			
		||||
  line-height: 72rpx;
 | 
			
		||||
  padding-left: 28rpx;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  color: #999;
 | 
			
		||||
}
 | 
			
		||||
.stepper-info {
 | 
			
		||||
  margin-left: auto;
 | 
			
		||||
}
 | 
			
		||||
.invalid-goods-wrap {
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
  margin-top: 40rpx;
 | 
			
		||||
}
 | 
			
		||||
.invalid-goods-wrap .invalid-head {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  padding: 30rpx 20rpx;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  border-bottom: 2rpx solid #f6f6f6;
 | 
			
		||||
}
 | 
			
		||||
.invalid-goods-wrap .invalid-head .invalid-title {
 | 
			
		||||
  color: #333;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  font-weight: 600;
 | 
			
		||||
}
 | 
			
		||||
.invalid-goods-wrap .invalid-head .invalid-clear {
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
}
 | 
			
		||||
.invalid-goods-wrap .toggle {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  height: 80rpx;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
}
 | 
			
		||||
.invalid-goods-wrap .toggle .m-r-6 {
 | 
			
		||||
  margin-right: 6rpx;
 | 
			
		||||
}
 | 
			
		||||
.invalid-goods-wrap .toggle .top-icon {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  width: 0;
 | 
			
		||||
  height: 0;
 | 
			
		||||
  border-left: 10rpx solid transparent;
 | 
			
		||||
  border-right: 10rpx solid transparent;
 | 
			
		||||
  border-bottom: 10rpx solid #fa4126;
 | 
			
		||||
}
 | 
			
		||||
.invalid-goods-wrap .toggle .down-icon {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  width: 0;
 | 
			
		||||
  height: 0;
 | 
			
		||||
  border-left: 10rpx solid transparent;
 | 
			
		||||
  border-right: 10rpx solid transparent;
 | 
			
		||||
  border-top: 10rpx solid #fa4126;
 | 
			
		||||
}
 | 
			
		||||
.action-btn {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
.action-btn .action-btn-arrow {
 | 
			
		||||
  font-size: 20rpx;
 | 
			
		||||
  margin-left: 8rpx;
 | 
			
		||||
}
 | 
			
		||||
.action-btn--active {
 | 
			
		||||
  opacity: 0.5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.swiper-right-del {
 | 
			
		||||
  height: calc(100% - 40rpx);
 | 
			
		||||
  width: 144rpx;
 | 
			
		||||
  background-color: #fa4126;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  color: white;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
.goods-stepper .stepper {
 | 
			
		||||
  border: none;
 | 
			
		||||
  border-radius: 0;
 | 
			
		||||
  height: auto;
 | 
			
		||||
  width: 168rpx;
 | 
			
		||||
  overflow: visible;
 | 
			
		||||
}
 | 
			
		||||
.goods-stepper .stepper .stepper__minus,
 | 
			
		||||
.goods-stepper .stepper .stepper__plus {
 | 
			
		||||
  width: 44rpx;
 | 
			
		||||
  height: 44rpx;
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
}
 | 
			
		||||
.goods-stepper .stepper .stepper__minus--hover,
 | 
			
		||||
.goods-stepper .stepper .stepper__plus--hover {
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
}
 | 
			
		||||
.goods-stepper .stepper .stepper__minus .wr-icon,
 | 
			
		||||
.goods-stepper .stepper .stepper__plus .wr-icon {
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
.goods-stepper .stepper .stepper__minus {
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
.goods-stepper .stepper .stepper__minus::after {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  display: block;
 | 
			
		||||
  content: ' ';
 | 
			
		||||
  left: -20rpx;
 | 
			
		||||
  right: -5rpx;
 | 
			
		||||
  top: -20rpx;
 | 
			
		||||
  bottom: -20rpx;
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
}
 | 
			
		||||
.goods-stepper .stepper .stepper__plus {
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
.goods-stepper .stepper .stepper__plus::after {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  display: block;
 | 
			
		||||
  content: ' ';
 | 
			
		||||
  left: -5rpx;
 | 
			
		||||
  right: -20rpx;
 | 
			
		||||
  top: -20rpx;
 | 
			
		||||
  bottom: -20rpx;
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
}
 | 
			
		||||
.goods-stepper .stepper .stepper__input {
 | 
			
		||||
  width: 72rpx;
 | 
			
		||||
  height: 44rpx;
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  color: #222427;
 | 
			
		||||
  font-weight: 600;
 | 
			
		||||
  border-left: none;
 | 
			
		||||
  border-right: none;
 | 
			
		||||
  min-height: 40rpx;
 | 
			
		||||
  margin: 0 4rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-sku-info .no-storage-mask {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  bottom: 0rpx;
 | 
			
		||||
  left: 0rpx;
 | 
			
		||||
  background-color: rgba(0, 0, 0, 0.1);
 | 
			
		||||
  height: 192rpx;
 | 
			
		||||
  width: 192rpx;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.no-storage-mask .no-storage-content {
 | 
			
		||||
  width: 128rpx;
 | 
			
		||||
  height: 128rpx;
 | 
			
		||||
  border-radius: 64rpx;
 | 
			
		||||
  background-color: rgba(0, 0, 0, 0.4);
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  line-height: 128rpx;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								mini-program/pages/cart/components/cart-group/utils.wxs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								mini-program/pages/cart/components/cart-group/utils.wxs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
module.exports.slice = function(arr) {
 | 
			
		||||
  return arr.slice(0, 2);
 | 
			
		||||
};
 | 
			
		||||
module.exports.imgCut = function(url, width, height) {
 | 
			
		||||
  if (url && (url.slice(0, 5) === 'http:' || url.slice(0, 6) === 'https:' || url.slice(0, 2) === '//')) {
 | 
			
		||||
    var argsStr = 'imageMogr2/thumbnail/!' + width +  'x' + height + 'r';
 | 
			
		||||
    if (url.indexOf('?') > -1) {
 | 
			
		||||
      url = url + '&' + argsStr;
 | 
			
		||||
    } else {
 | 
			
		||||
      url = url + '?' + argsStr;
 | 
			
		||||
    }
 | 
			
		||||
    if (url.slice(0, 5) === 'http:') {
 | 
			
		||||
      url = 'https://' + url.slice(5)
 | 
			
		||||
    }
 | 
			
		||||
    if (url.slice(0, 2) === '//') {
 | 
			
		||||
      url = 'https:' + url
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return url;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										243
									
								
								mini-program/pages/cart/components/goods-card/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										243
									
								
								mini-program/pages/cart/components/goods-card/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,243 @@
 | 
			
		||||
Component({
 | 
			
		||||
  options: {
 | 
			
		||||
    multipleSlots: true, // 在组件定义时的选项中启用多slot支持
 | 
			
		||||
    addGlobalClass: true,
 | 
			
		||||
  },
 | 
			
		||||
  intersectionObserverContext: null,
 | 
			
		||||
 | 
			
		||||
  externalClasses: [
 | 
			
		||||
    'card-class',
 | 
			
		||||
    'title-class',
 | 
			
		||||
    'desc-class',
 | 
			
		||||
    'num-class',
 | 
			
		||||
    'thumb-class',
 | 
			
		||||
    'specs-class',
 | 
			
		||||
    'price-class',
 | 
			
		||||
    'origin-price-class',
 | 
			
		||||
    'price-prefix-class',
 | 
			
		||||
  ],
 | 
			
		||||
 | 
			
		||||
  properties: {
 | 
			
		||||
    hidden: {
 | 
			
		||||
      // 设置为null代表不做类型转换
 | 
			
		||||
      type: null,
 | 
			
		||||
      value: false,
 | 
			
		||||
      observer(hidden) {
 | 
			
		||||
        // null就是代表没有设置,没有设置的话不setData,防止祖先组件触发的setHidden操作被覆盖
 | 
			
		||||
        if (hidden !== null) {
 | 
			
		||||
          this.setHidden(!!hidden);
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    id: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      // `goods-card-88888888`
 | 
			
		||||
      // 不能在这里写生成逻辑,如果在这里写,那么假设有多个goods-list时,他们将共享这个值
 | 
			
		||||
      value: '',
 | 
			
		||||
      observer: (id) => {
 | 
			
		||||
        this.genIndependentID(id);
 | 
			
		||||
        if (this.properties.thresholds?.length) {
 | 
			
		||||
          this.createIntersectionObserverHandle();
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    data: {
 | 
			
		||||
      type: Object,
 | 
			
		||||
      observer(goods) {
 | 
			
		||||
        // 有ID的商品才渲染
 | 
			
		||||
        if (!goods) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /** 划线价是否有效 */
 | 
			
		||||
        let isValidityLinePrice = true;
 | 
			
		||||
        // 判断一次划线价格是否合理
 | 
			
		||||
        if (
 | 
			
		||||
          goods.originPrice &&
 | 
			
		||||
          goods.price &&
 | 
			
		||||
          goods.originPrice < goods.price
 | 
			
		||||
        ) {
 | 
			
		||||
          isValidityLinePrice = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 敲定换行数量默认值
 | 
			
		||||
        if (goods.lineClamp === undefined || goods.lineClamp <= 0) {
 | 
			
		||||
          // tag数组长度 大于0 且 可见
 | 
			
		||||
          // 指定换行为1行
 | 
			
		||||
          if ((goods.tags?.length || 0) > 0 && !goods.hideKey?.tags) {
 | 
			
		||||
            goods.lineClamp = 1;
 | 
			
		||||
          } else {
 | 
			
		||||
            goods.lineClamp = 2;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.setData({ goods, isValidityLinePrice });
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    layout: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: 'horizontal',
 | 
			
		||||
    },
 | 
			
		||||
    thumbMode: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: 'aspectFill',
 | 
			
		||||
    },
 | 
			
		||||
    priceFill: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      value: true,
 | 
			
		||||
    },
 | 
			
		||||
    currency: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '¥',
 | 
			
		||||
    },
 | 
			
		||||
    lazyLoad: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      value: false,
 | 
			
		||||
    },
 | 
			
		||||
    centered: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      value: false,
 | 
			
		||||
    },
 | 
			
		||||
    pricePrefix: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
    /** 元素可见监控阈值, 数组长度大于0就创建 */
 | 
			
		||||
    thresholds: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      value: [],
 | 
			
		||||
      observer(current) {
 | 
			
		||||
        if (current && current.length) {
 | 
			
		||||
          this.createIntersectionObserverHandle();
 | 
			
		||||
        } else {
 | 
			
		||||
          this.clearIntersectionObserverHandle();
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    specsIconClassPrefix: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: 'wr',
 | 
			
		||||
    },
 | 
			
		||||
    specsIcon: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: 'expand_more',
 | 
			
		||||
    },
 | 
			
		||||
    addCartIconClassPrefix: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: 'wr',
 | 
			
		||||
    },
 | 
			
		||||
    addCartIcon: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: 'cart',
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  data: {
 | 
			
		||||
    hiddenInData: false,
 | 
			
		||||
    independentID: '',
 | 
			
		||||
    goods: { id: '' },
 | 
			
		||||
    /** 保证划线价格不小于原价,否则不渲染划线价 */
 | 
			
		||||
    isValidityLinePrice: false,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  lifetimes: {
 | 
			
		||||
    ready() {
 | 
			
		||||
      this.init();
 | 
			
		||||
    },
 | 
			
		||||
    detached() {
 | 
			
		||||
      this.clear();
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    clickHandle() {
 | 
			
		||||
      this.triggerEvent('click', { goods: this.data.goods });
 | 
			
		||||
    },
 | 
			
		||||
    clickThumbHandle() {
 | 
			
		||||
      this.triggerEvent('thumb', { goods: this.data.goods });
 | 
			
		||||
    },
 | 
			
		||||
    clickSpecsHandle() {
 | 
			
		||||
      this.triggerEvent('specs', { goods: this.data.goods });
 | 
			
		||||
    },
 | 
			
		||||
    clickTagHandle(evt) {
 | 
			
		||||
      const { index } = evt.currentTarget.dataset;
 | 
			
		||||
      this.triggerEvent('tag', { goods: this.data.goods, index });
 | 
			
		||||
    },
 | 
			
		||||
    // 加入购物车
 | 
			
		||||
    addCartHandle(e) {
 | 
			
		||||
      const { id } = e.currentTarget;
 | 
			
		||||
      const { id: cardID } = e.currentTarget.dataset;
 | 
			
		||||
      this.triggerEvent('add-cart', {
 | 
			
		||||
        ...e.detail,
 | 
			
		||||
        id,
 | 
			
		||||
        cardID,
 | 
			
		||||
        goods: this.data.goods,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    genIndependentID(id, cb) {
 | 
			
		||||
      let independentID;
 | 
			
		||||
      if (id) {
 | 
			
		||||
        independentID = id;
 | 
			
		||||
      } else {
 | 
			
		||||
        independentID = `goods-card-${~~(Math.random() * 10 ** 8)}`;
 | 
			
		||||
      }
 | 
			
		||||
      this.setData({ independentID }, cb);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    init() {
 | 
			
		||||
      const { thresholds, id, hidden } = this.properties;
 | 
			
		||||
      if (hidden !== null) {
 | 
			
		||||
        this.setHidden(!!hidden);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.genIndependentID(id || '', () => {
 | 
			
		||||
        if (thresholds && thresholds.length) {
 | 
			
		||||
          this.createIntersectionObserverHandle();
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    clear() {
 | 
			
		||||
      this.clearIntersectionObserverHandle();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setHidden(hidden) {
 | 
			
		||||
      this.setData({ hiddenInData: !!hidden });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createIntersectionObserverHandle() {
 | 
			
		||||
      if (this.intersectionObserverContext || !this.data.independentID) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.intersectionObserverContext = wx
 | 
			
		||||
        .createIntersectionObserver(this, {
 | 
			
		||||
          thresholds: this.properties.thresholds,
 | 
			
		||||
        })
 | 
			
		||||
        .relativeToViewport();
 | 
			
		||||
 | 
			
		||||
      this.intersectionObserverContext.observe(
 | 
			
		||||
        `#${this.data.independentID}`,
 | 
			
		||||
        (res) => {
 | 
			
		||||
          this.intersectionObserverCB(res);
 | 
			
		||||
        },
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
    intersectionObserverCB(ob) {
 | 
			
		||||
      this.triggerEvent('ob', {
 | 
			
		||||
        goods: this.data.goods,
 | 
			
		||||
        context: this.intersectionObserverContext,
 | 
			
		||||
        ob,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    clearIntersectionObserverHandle() {
 | 
			
		||||
      if (this.intersectionObserverContext) {
 | 
			
		||||
        try {
 | 
			
		||||
          this.intersectionObserverContext.disconnect();
 | 
			
		||||
        } catch (e) {}
 | 
			
		||||
 | 
			
		||||
        this.intersectionObserverContext = null;
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										9
									
								
								mini-program/pages/cart/components/goods-card/index.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								mini-program/pages/cart/components/goods-card/index.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "price": "/components/price/index",
 | 
			
		||||
    "t-tag": "tdesign-miniprogram/tag/tag",
 | 
			
		||||
    "t-image": "/components/webp-image/index",
 | 
			
		||||
    "t-icon": "tdesign-miniprogram/icon/icon"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										75
									
								
								mini-program/pages/cart/components/goods-card/index.wxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								mini-program/pages/cart/components/goods-card/index.wxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
			
		||||
<view
 | 
			
		||||
  id="{{independentID}}"
 | 
			
		||||
  class="wr-goods-card card-class {{ layout }} {{ centered ? 'center' : ''}}"
 | 
			
		||||
  bind:tap="clickHandle"
 | 
			
		||||
  data-goods="{{ goods }}"
 | 
			
		||||
  hidden="{{hiddenInData}}"
 | 
			
		||||
>
 | 
			
		||||
	<view class="wr-goods-card__main">
 | 
			
		||||
		<view class="wr-goods-card__thumb thumb-class" bind:tap="clickThumbHandle">
 | 
			
		||||
			<!-- data-src 是方便加购动画读取图片用的 -->
 | 
			
		||||
			<t-image
 | 
			
		||||
			  t-class="wr-goods-card__thumb-com"
 | 
			
		||||
			  wx:if="{{ !!goods.thumb && !goods.hideKey.thumb }}"
 | 
			
		||||
			  src="{{ goods.thumb }}"
 | 
			
		||||
			  mode="{{ thumbMode }}"
 | 
			
		||||
			  lazy-load="{{ lazyLoad }}"
 | 
			
		||||
			/>
 | 
			
		||||
			<slot name="thumb-cover" />
 | 
			
		||||
		</view>
 | 
			
		||||
		<view class="wr-goods-card__body">
 | 
			
		||||
			<view class="wr-goods-card__long_content">
 | 
			
		||||
				<view wx:if="{{ goods.title && !goods.hideKey.title }}" class="wr-goods-card__title title-class" style="-webkit-line-clamp: {{ goods.lineClamp }};">
 | 
			
		||||
					<slot name="before-title" />
 | 
			
		||||
					{{ goods.title }}
 | 
			
		||||
				</view>
 | 
			
		||||
				<slot name="after-title" />
 | 
			
		||||
				<view wx:if="{{ goods.desc && !goods.hideKey.desc }}" class="wr-goods-card__desc desc-class">{{ goods.desc }}</view>
 | 
			
		||||
				<slot name="after-desc" />
 | 
			
		||||
				<view wx:if="{{ goods.specs && goods.specs.length > 0 && !goods.hideKey.specs }}" class="wr-goods-card__specs__desc specs-class" bind:tap="clickSpecsHandle">
 | 
			
		||||
					<view class="wr-goods-card__specs__desc-text">{{ goods.specs }}</view>
 | 
			
		||||
					<t-icon name="chevron-down" size="32rpx" color="#999999" />
 | 
			
		||||
				</view>
 | 
			
		||||
				<view class="goods_tips" wx:if="{{goods.stockQuantity !== 0 && goods.quantity >= goods.stockQuantity}}">库存不足</view>
 | 
			
		||||
			</view>
 | 
			
		||||
			<view class="wr-goods-card__short_content">
 | 
			
		||||
				<block wx:if="{{goods.stockQuantity !== 0}}">
 | 
			
		||||
					<view wx:if="{{ pricePrefix }}" class="wr-goods-card__price__prefix price-prefix-class">{{ pricePrefix }}</view>
 | 
			
		||||
					<slot name="price-prefix" />
 | 
			
		||||
					<view wx:if="{{ goods.price && !goods.hideKey.price }}" class="wr-goods-card__price">
 | 
			
		||||
						<price
 | 
			
		||||
						  wr-class="price-class"
 | 
			
		||||
						  symbol="{{currency}}"
 | 
			
		||||
						  price="{{goods.price}}"
 | 
			
		||||
						  fill="{{priceFill}}"
 | 
			
		||||
						  decimalSmaller
 | 
			
		||||
						/>
 | 
			
		||||
					</view>
 | 
			
		||||
					<view wx:if="{{ goods.originPrice && !goods.hideKey.originPrice && isValidityLinePrice }}" class="wr-goods-card__origin-price">
 | 
			
		||||
						<price
 | 
			
		||||
						  wr-class="origin-price-class"
 | 
			
		||||
						  symbol="{{currency}}"
 | 
			
		||||
						  price="{{goods.originPrice}}"
 | 
			
		||||
						  fill="{{priceFill}}"
 | 
			
		||||
						/>
 | 
			
		||||
					</view>
 | 
			
		||||
					<slot name="origin-price" />
 | 
			
		||||
					<view wx:if="{{goods.num && !goods.hideKey.num}}" class="wr-goods-card__num num-class">
 | 
			
		||||
						<text class="wr-goods-card__num__prefix">x </text>
 | 
			
		||||
						{{ goods.num }}
 | 
			
		||||
					</view>
 | 
			
		||||
				</block>
 | 
			
		||||
				<block wx:else>
 | 
			
		||||
					<view class="no_storage">
 | 
			
		||||
						<view>请重新选择商品规格</view>
 | 
			
		||||
						<view class="no_storage__right">重选</view>
 | 
			
		||||
					</view>
 | 
			
		||||
				</block>
 | 
			
		||||
			</view>
 | 
			
		||||
			<slot name="append-body" />
 | 
			
		||||
		</view>
 | 
			
		||||
		<slot name="footer" />
 | 
			
		||||
	</view>
 | 
			
		||||
	<slot name="append-card" />
 | 
			
		||||
</view>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										260
									
								
								mini-program/pages/cart/components/goods-card/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										260
									
								
								mini-program/pages/cart/components/goods-card/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,260 @@
 | 
			
		||||
.wr-goods-card {
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
/*  */
 | 
			
		||||
.wr-goods-card__main {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  padding: 0;
 | 
			
		||||
  background: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.wr-goods-card.center .wr-goods-card__main {
 | 
			
		||||
  align-items: flex-start;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.wr-goods-card__thumb {
 | 
			
		||||
  flex-shrink: 0;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  width: 140rpx;
 | 
			
		||||
  height: 140rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.wr-goods-card__thumb-com {
 | 
			
		||||
  width: 192rpx;
 | 
			
		||||
  height: 192rpx;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card__thumb:empty {
 | 
			
		||||
  display: none;
 | 
			
		||||
  margin: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.wr-goods-card__body {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  margin: 0 0 0 20rpx;
 | 
			
		||||
  flex-direction: row;
 | 
			
		||||
  flex: 1 1 auto;
 | 
			
		||||
  min-height: 192rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.wr-goods-card__long_content {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  flex: 1 1 auto;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card__long_content .goods_tips {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  margin-top: 16rpx;
 | 
			
		||||
  text-align: right;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  line-height: 32rpx;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card__title {
 | 
			
		||||
  flex-shrink: 0;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  color: #333;
 | 
			
		||||
  line-height: 40rpx;
 | 
			
		||||
  font-weight: 400;
 | 
			
		||||
  display: -webkit-box;
 | 
			
		||||
  -webkit-box-orient: vertical;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  word-break: break-word;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card__title__prefix-tags {
 | 
			
		||||
  display: inline-flex;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card__title__prefix-tags .prefix-tag {
 | 
			
		||||
  margin: 0 8rpx 0 0;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card__desc {
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  color: #f5f5f5;
 | 
			
		||||
  line-height: 40rpx;
 | 
			
		||||
  display: -webkit-box;
 | 
			
		||||
  -webkit-box-orient: vertical;
 | 
			
		||||
  -webkit-line-clamp: 2;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card__specs__desc,
 | 
			
		||||
.wr-goods-card__specs__text {
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  height: 32rpx;
 | 
			
		||||
  line-height: 32rpx;
 | 
			
		||||
  color: #999999;
 | 
			
		||||
  margin: 8rpx 0;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card__specs__desc {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-self: flex-start;
 | 
			
		||||
  flex-direction: row;
 | 
			
		||||
  background: #f5f5f5;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
  padding: 4rpx 8rpx;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card__specs__desc-text {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  max-width: 380rpx;
 | 
			
		||||
  word-break: break-all;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  display: -webkit-box;
 | 
			
		||||
  -webkit-box-orient: vertical;
 | 
			
		||||
  -webkit-line-clamp: 1;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card__specs__desc-icon {
 | 
			
		||||
  line-height: inherit;
 | 
			
		||||
  margin-left: 8rpx;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  color: #bbb;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card__specs__text {
 | 
			
		||||
  display: -webkit-box;
 | 
			
		||||
  -webkit-box-orient: vertical;
 | 
			
		||||
  -webkit-line-clamp: 1;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  text-overflow: ellipsis;
 | 
			
		||||
  word-break: break-all;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card__tags {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: row;
 | 
			
		||||
  flex-wrap: wrap;
 | 
			
		||||
  margin: 16rpx 0 0 0;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card__tag {
 | 
			
		||||
  color: #fa550f;
 | 
			
		||||
  background: transparent;
 | 
			
		||||
  font-size: 20rpx;
 | 
			
		||||
  border: 1rpx solid #fa550f;
 | 
			
		||||
  padding: 0 8rpx;
 | 
			
		||||
  height: 30rpx;
 | 
			
		||||
  line-height: 30rpx;
 | 
			
		||||
  margin: 0 8rpx 8rpx 0;
 | 
			
		||||
  display: block;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
  word-break: keep-all;
 | 
			
		||||
  text-overflow: ellipsis;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card__short_content {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  justify-content: flex-start;
 | 
			
		||||
  align-items: flex-end;
 | 
			
		||||
  margin: 0 0 0 46rpx;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card__price__prefix {
 | 
			
		||||
  order: 0;
 | 
			
		||||
  color: #666;
 | 
			
		||||
  margin: 0;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card__price {
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  order: 1;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
  font-size: 36rpx;
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  line-height: 48rpx;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card__origin-price {
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
  order: 2;
 | 
			
		||||
  color: #aaaaaa;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  margin: 0;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card__num {
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
  order: 4;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  color: #999;
 | 
			
		||||
  margin: 20rpx 0 0 auto;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card__num__prefix {
 | 
			
		||||
  color: inherit;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card__add-cart {
 | 
			
		||||
  order: 3;
 | 
			
		||||
  margin: auto 0 0 auto;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card.horizontal-wrap .wr-goods-card__thumb {
 | 
			
		||||
  width: 192rpx;
 | 
			
		||||
  height: 192rpx;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card.horizontal-wrap .wr-goods-card__body {
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card.horizontal-wrap .wr-goods-card__short_content {
 | 
			
		||||
  flex-direction: row;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  margin: 16rpx 0 0 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.wr-goods-card.horizontal-wrap .wr-goods-card__num {
 | 
			
		||||
  margin: 0 0 0 auto;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card.vertical .wr-goods-card__main {
 | 
			
		||||
  padding: 0 0 22rpx 0;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card.vertical .wr-goods-card__thumb {
 | 
			
		||||
  width: 340rpx;
 | 
			
		||||
  height: 340rpx;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card.vertical .wr-goods-card__body {
 | 
			
		||||
  margin: 20rpx 20rpx 0 20rpx;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card.vertical .wr-goods-card__long_content {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card.vertical .wr-goods-card__title {
 | 
			
		||||
  line-height: 36rpx;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card.vertical .wr-goods-card__short_content {
 | 
			
		||||
  margin: 20rpx 0 0 0;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card.vertical .wr-goods-card__price {
 | 
			
		||||
  order: 2;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
  margin: 20rpx 0 0 0;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card.vertical .wr-goods-card__origin-price {
 | 
			
		||||
  order: 1;
 | 
			
		||||
}
 | 
			
		||||
.wr-goods-card.vertical .wr-goods-card__add-cart {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  bottom: 20rpx;
 | 
			
		||||
  right: 20rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.wr-goods-card__short_content .no_storage {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  height: 40rpx;
 | 
			
		||||
  color: #333;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  line-height: 32rpx;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.no_storage .no_storage__right {
 | 
			
		||||
  width: 80rpx;
 | 
			
		||||
  height: 40rpx;
 | 
			
		||||
  border-radius: 20rpx;
 | 
			
		||||
  border: 2rpx solid #fa4126;
 | 
			
		||||
  line-height: 40rpx;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										72
									
								
								mini-program/pages/cart/components/specs-popup/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								mini-program/pages/cart/components/specs-popup/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,72 @@
 | 
			
		||||
Component({
 | 
			
		||||
  options: {
 | 
			
		||||
    addGlobalClass: true,
 | 
			
		||||
    multipleSlots: true, // 在组件定义时的选项中启用多slot支持
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  properties: {
 | 
			
		||||
    show: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      value: false,
 | 
			
		||||
    },
 | 
			
		||||
    value: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
    title: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      observer(newVal) {
 | 
			
		||||
        this.setData({ 'goods.title': newVal });
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    price: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '',
 | 
			
		||||
      observer(newVal) {
 | 
			
		||||
        this.setData({ 'goods.price': newVal });
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    thumb: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '',
 | 
			
		||||
      observer(newVal) {
 | 
			
		||||
        this.setData({ 'goods.thumb': newVal });
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    thumbMode: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: 'aspectFit',
 | 
			
		||||
    },
 | 
			
		||||
    zIndex: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      value: 99,
 | 
			
		||||
    },
 | 
			
		||||
    specs: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      value: [],
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  data: {
 | 
			
		||||
    goods: {
 | 
			
		||||
      title: '',
 | 
			
		||||
      thumb: '',
 | 
			
		||||
      price: '',
 | 
			
		||||
      hideKey: {
 | 
			
		||||
        originPrice: true,
 | 
			
		||||
        tags: true,
 | 
			
		||||
        specs: true,
 | 
			
		||||
        num: true,
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    onClose() {
 | 
			
		||||
      this.triggerEvent('close');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onCloseOver() {
 | 
			
		||||
      this.triggerEvent('closeover');
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "t-popup": "tdesign-miniprogram/popup/popup",
 | 
			
		||||
    "goods-card": "../../components/goods-card/index"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								mini-program/pages/cart/components/specs-popup/index.wxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								mini-program/pages/cart/components/specs-popup/index.wxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
<t-popup
 | 
			
		||||
  close-on-overlay-click="{{true}}"
 | 
			
		||||
  visible="{{show}}"
 | 
			
		||||
  placement="bottom"
 | 
			
		||||
  z-index="{{zIndex}}"
 | 
			
		||||
>
 | 
			
		||||
	<view class="specs-popup">
 | 
			
		||||
		<view>
 | 
			
		||||
			<goods-card data="{{goods}}" layout="horizontal-wrap" thumb-mode="{{thumbMode}}" />
 | 
			
		||||
			<view class="section">
 | 
			
		||||
				<view class="title">已选规格</view>
 | 
			
		||||
				<view class="options">
 | 
			
		||||
					<view
 | 
			
		||||
					  wx:for="{{specs}}"
 | 
			
		||||
					  wx:for-item="spec"
 | 
			
		||||
					  wx:key="spec"
 | 
			
		||||
					  class="option"
 | 
			
		||||
					>{{spec}}
 | 
			
		||||
					</view>
 | 
			
		||||
				</view>
 | 
			
		||||
			</view>
 | 
			
		||||
		</view>
 | 
			
		||||
		<view class="bottom-btn" hover-class="bottom-btn--active" bindtap="onClose">我知道了</view>
 | 
			
		||||
	</view>
 | 
			
		||||
</t-popup>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										68
									
								
								mini-program/pages/cart/components/specs-popup/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								mini-program/pages/cart/components/specs-popup/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
.specs-popup {
 | 
			
		||||
  width: 100vw;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  padding: 32rpx 32rpx calc(20rpx + env(safe-area-inset-bottom)) 32rpx;
 | 
			
		||||
  max-height: 80vh;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  background-color: white;
 | 
			
		||||
  border-radius: 20rpx 20rpx 0 0;
 | 
			
		||||
}
 | 
			
		||||
.specs-popup .section {
 | 
			
		||||
  margin-top: 44rpx;
 | 
			
		||||
  flex: auto;
 | 
			
		||||
  overflow-y: scroll;
 | 
			
		||||
  overflow-x: hidden;
 | 
			
		||||
  -webkit-overflow-scrolling: touch;
 | 
			
		||||
}
 | 
			
		||||
.specs-popup .section .title {
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  color: #4f5356;
 | 
			
		||||
}
 | 
			
		||||
.specs-popup .section .options {
 | 
			
		||||
  color: #333333;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  margin-right: -26rpx;
 | 
			
		||||
}
 | 
			
		||||
.specs-popup .section .options .option {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  margin-top: 24rpx;
 | 
			
		||||
  height: 56rpx;
 | 
			
		||||
  line-height: 56rpx;
 | 
			
		||||
  padding: 0 16rpx;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
  max-width: 100%;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  text-overflow: ellipsis;
 | 
			
		||||
}
 | 
			
		||||
.specs-popup .section .options .option:not(:last-child) {
 | 
			
		||||
  margin-right: 26rpx;
 | 
			
		||||
}
 | 
			
		||||
.specs-popup .bottom-btn {
 | 
			
		||||
  margin-top: 42rpx;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  height: 80rpx;
 | 
			
		||||
  line-height: 80rpx;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  background-color: white;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
}
 | 
			
		||||
.specs-popup .bottom-btn--active {
 | 
			
		||||
  opacity: 0.5;
 | 
			
		||||
}
 | 
			
		||||
.specs-popup .bottom-btn::after {
 | 
			
		||||
  display: block;
 | 
			
		||||
  content: ' ';
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  width: 200%;
 | 
			
		||||
  height: 200%;
 | 
			
		||||
  border: 1px solid #fa4126;
 | 
			
		||||
  border-radius: 80rpx;
 | 
			
		||||
  transform: scale(0.5);
 | 
			
		||||
  transform-origin: left top;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										294
									
								
								mini-program/pages/cart/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										294
									
								
								mini-program/pages/cart/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,294 @@
 | 
			
		||||
import Dialog from 'tdesign-miniprogram/dialog/index';
 | 
			
		||||
import Toast from 'tdesign-miniprogram/toast/index';
 | 
			
		||||
import { fetchCartGroupData } from '../../services/cart/cart';
 | 
			
		||||
 | 
			
		||||
Page({
 | 
			
		||||
  data: {
 | 
			
		||||
    cartGroupData: null,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // 调用自定义tabbar的init函数,使页面与tabbar激活状态保持一致
 | 
			
		||||
  onShow() {
 | 
			
		||||
    this.getTabBar().init();
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onLoad() {
 | 
			
		||||
    this.refreshData();
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  refreshData() {
 | 
			
		||||
    this.getCartGroupData().then((res) => {
 | 
			
		||||
      let isEmpty = true;
 | 
			
		||||
      const cartGroupData = res.data;
 | 
			
		||||
      // 一些组件中需要的字段可能接口并没有返回,或者返回的数据结构与预期不一致,需要在此先对数据做一些处理
 | 
			
		||||
      // 统计门店下加购的商品是否全选、是否存在缺货/无货
 | 
			
		||||
      for (const store of cartGroupData.storeGoods) {
 | 
			
		||||
        store.isSelected = true; // 该门店已加购商品是否全选
 | 
			
		||||
        store.storeStockShortage = false; // 该门店已加购商品是否存在库存不足
 | 
			
		||||
        if (!store.shortageGoodsList) {
 | 
			
		||||
          store.shortageGoodsList = []; // 该门店已加购商品如果库存为0需单独分组
 | 
			
		||||
        }
 | 
			
		||||
        for (const activity of store.promotionGoodsList) {
 | 
			
		||||
          activity.goodsPromotionList = activity.goodsPromotionList.filter((goods) => {
 | 
			
		||||
            goods.originPrice = undefined;
 | 
			
		||||
 | 
			
		||||
            // 统计是否有加购数大于库存数的商品
 | 
			
		||||
            if (goods.quantity > goods.stockQuantity) {
 | 
			
		||||
              store.storeStockShortage = true;
 | 
			
		||||
            }
 | 
			
		||||
            // 统计是否全选
 | 
			
		||||
            if (!goods.isSelected) {
 | 
			
		||||
              store.isSelected = false;
 | 
			
		||||
            }
 | 
			
		||||
            // 库存为0(无货)的商品单独分组
 | 
			
		||||
            if (goods.stockQuantity > 0) {
 | 
			
		||||
              return true;
 | 
			
		||||
            }
 | 
			
		||||
            store.shortageGoodsList.push(goods);
 | 
			
		||||
            return false;
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
          if (activity.goodsPromotionList.length > 0) {
 | 
			
		||||
            isEmpty = false;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        if (store.shortageGoodsList.length > 0) {
 | 
			
		||||
          isEmpty = false;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      cartGroupData.invalidGoodItems = cartGroupData.invalidGoodItems.map((goods) => {
 | 
			
		||||
        goods.originPrice = undefined;
 | 
			
		||||
        return goods;
 | 
			
		||||
      });
 | 
			
		||||
      cartGroupData.isNotEmpty = !isEmpty;
 | 
			
		||||
      this.setData({ cartGroupData });
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  findGoods(spuId, skuId) {
 | 
			
		||||
    let currentStore;
 | 
			
		||||
    let currentActivity;
 | 
			
		||||
    let currentGoods;
 | 
			
		||||
    const { storeGoods } = this.data.cartGroupData;
 | 
			
		||||
    for (const store of storeGoods) {
 | 
			
		||||
      for (const activity of store.promotionGoodsList) {
 | 
			
		||||
        for (const goods of activity.goodsPromotionList) {
 | 
			
		||||
          if (goods.spuId === spuId && goods.skuId === skuId) {
 | 
			
		||||
            currentStore = store;
 | 
			
		||||
            currentActivity = currentActivity;
 | 
			
		||||
            currentGoods = goods;
 | 
			
		||||
            return {
 | 
			
		||||
              currentStore,
 | 
			
		||||
              currentActivity,
 | 
			
		||||
              currentGoods,
 | 
			
		||||
            };
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return {
 | 
			
		||||
      currentStore,
 | 
			
		||||
      currentActivity,
 | 
			
		||||
      currentGoods,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // 注:实际场景时应该调用接口获取购物车数据
 | 
			
		||||
  getCartGroupData() {
 | 
			
		||||
    const { cartGroupData } = this.data;
 | 
			
		||||
    if (!cartGroupData) {
 | 
			
		||||
      return fetchCartGroupData();
 | 
			
		||||
    }
 | 
			
		||||
    return Promise.resolve({ data: cartGroupData });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // 选择单个商品
 | 
			
		||||
  // 注:实际场景时应该调用接口更改选中状态
 | 
			
		||||
  selectGoodsService({ spuId, skuId, isSelected }) {
 | 
			
		||||
    this.findGoods(spuId, skuId).currentGoods.isSelected = isSelected;
 | 
			
		||||
    return Promise.resolve();
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // 全选门店
 | 
			
		||||
  // 注:实际场景时应该调用接口更改选中状态
 | 
			
		||||
  selectStoreService({ storeId, isSelected }) {
 | 
			
		||||
    const currentStore = this.data.cartGroupData.storeGoods.find((s) => s.storeId === storeId);
 | 
			
		||||
    currentStore.isSelected = isSelected;
 | 
			
		||||
    currentStore.promotionGoodsList.forEach((activity) => {
 | 
			
		||||
      activity.goodsPromotionList.forEach((goods) => {
 | 
			
		||||
        goods.isSelected = isSelected;
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    return Promise.resolve();
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // 加购数量变更
 | 
			
		||||
  // 注:实际场景时应该调用接口
 | 
			
		||||
  changeQuantityService({ spuId, skuId, quantity }) {
 | 
			
		||||
    this.findGoods(spuId, skuId).currentGoods.quantity = quantity;
 | 
			
		||||
    return Promise.resolve();
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // 删除加购商品
 | 
			
		||||
  // 注:实际场景时应该调用接口
 | 
			
		||||
  deleteGoodsService({ spuId, skuId }) {
 | 
			
		||||
    function deleteGoods(group) {
 | 
			
		||||
      for (const gindex in group) {
 | 
			
		||||
        const goods = group[gindex];
 | 
			
		||||
        if (goods.spuId === spuId && goods.skuId === skuId) {
 | 
			
		||||
          group.splice(gindex, 1);
 | 
			
		||||
          return gindex;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      return -1;
 | 
			
		||||
    }
 | 
			
		||||
    const { storeGoods, invalidGoodItems } = this.data.cartGroupData;
 | 
			
		||||
    for (const store of storeGoods) {
 | 
			
		||||
      for (const activity of store.promotionGoodsList) {
 | 
			
		||||
        if (deleteGoods(activity.goodsPromotionList) > -1) {
 | 
			
		||||
          return Promise.resolve();
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (deleteGoods(store.shortageGoodsList) > -1) {
 | 
			
		||||
        return Promise.resolve();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if (deleteGoods(invalidGoodItems) > -1) {
 | 
			
		||||
      return Promise.resolve();
 | 
			
		||||
    }
 | 
			
		||||
    return Promise.reject();
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // 清空失效商品
 | 
			
		||||
  // 注:实际场景时应该调用接口
 | 
			
		||||
  clearInvalidGoodsService() {
 | 
			
		||||
    this.data.cartGroupData.invalidGoodItems = [];
 | 
			
		||||
    return Promise.resolve();
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onGoodsSelect(e) {
 | 
			
		||||
    const {
 | 
			
		||||
      goods: { spuId, skuId },
 | 
			
		||||
      isSelected,
 | 
			
		||||
    } = e.detail;
 | 
			
		||||
    const { currentGoods } = this.findGoods(spuId, skuId);
 | 
			
		||||
    Toast({
 | 
			
		||||
      context: this,
 | 
			
		||||
      selector: '#t-toast',
 | 
			
		||||
      message: `${isSelected ? '选择' : '取消'}"${
 | 
			
		||||
        currentGoods.title.length > 5 ? `${currentGoods.title.slice(0, 5)}...` : currentGoods.title
 | 
			
		||||
      }"`,
 | 
			
		||||
      icon: '',
 | 
			
		||||
    });
 | 
			
		||||
    this.selectGoodsService({ spuId, skuId, isSelected }).then(() => this.refreshData());
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onStoreSelect(e) {
 | 
			
		||||
    const {
 | 
			
		||||
      store: { storeId },
 | 
			
		||||
      isSelected,
 | 
			
		||||
    } = e.detail;
 | 
			
		||||
    this.selectStoreService({ storeId, isSelected }).then(() => this.refreshData());
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onQuantityChange(e) {
 | 
			
		||||
    const {
 | 
			
		||||
      goods: { spuId, skuId },
 | 
			
		||||
      quantity,
 | 
			
		||||
    } = e.detail;
 | 
			
		||||
    const { currentGoods } = this.findGoods(spuId, skuId);
 | 
			
		||||
    const stockQuantity = currentGoods.stockQuantity > 0 ? currentGoods.stockQuantity : 0; // 避免后端返回的是-1
 | 
			
		||||
    // 加购数量超过库存数量
 | 
			
		||||
    if (quantity > stockQuantity) {
 | 
			
		||||
      // 加购数量等于库存数量的情况下继续加购
 | 
			
		||||
      if (currentGoods.quantity === stockQuantity && quantity - stockQuantity === 1) {
 | 
			
		||||
        Toast({
 | 
			
		||||
          context: this,
 | 
			
		||||
          selector: '#t-toast',
 | 
			
		||||
          message: '当前商品库存不足',
 | 
			
		||||
        });
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      Dialog.confirm({
 | 
			
		||||
        title: '商品库存不足',
 | 
			
		||||
        content: `当前商品库存不足,最大可购买数量为${stockQuantity}件`,
 | 
			
		||||
        confirmBtn: '修改为最大可购买数量',
 | 
			
		||||
        cancelBtn: '取消',
 | 
			
		||||
      })
 | 
			
		||||
        .then(() => {
 | 
			
		||||
          this.changeQuantityService({
 | 
			
		||||
            spuId,
 | 
			
		||||
            skuId,
 | 
			
		||||
            quantity: stockQuantity,
 | 
			
		||||
          }).then(() => this.refreshData());
 | 
			
		||||
        })
 | 
			
		||||
        .catch(() => {});
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    this.changeQuantityService({ spuId, skuId, quantity }).then(() => this.refreshData());
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  goCollect() {
 | 
			
		||||
    /** 活动肯定有一个活动ID,用来获取活动banner,活动商品列表等 */
 | 
			
		||||
    const promotionID = '123';
 | 
			
		||||
    wx.navigateTo({
 | 
			
		||||
      url: `/pages/promotion-detail/index?promotion_id=${promotionID}`,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  goGoodsDetail(e) {
 | 
			
		||||
    const { spuId, storeId } = e.detail.goods;
 | 
			
		||||
    wx.navigateTo({
 | 
			
		||||
      url: `/pages/goods/details/index?spuId=${spuId}&storeId=${storeId}`,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  clearInvalidGoods() {
 | 
			
		||||
    // 实际场景时应该调用接口清空失效商品
 | 
			
		||||
    this.clearInvalidGoodsService().then(() => this.refreshData());
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onGoodsDelete(e) {
 | 
			
		||||
    const {
 | 
			
		||||
      goods: { spuId, skuId },
 | 
			
		||||
    } = e.detail;
 | 
			
		||||
    Dialog.confirm({
 | 
			
		||||
      content: '确认删除该商品吗?',
 | 
			
		||||
      confirmBtn: '确定',
 | 
			
		||||
      cancelBtn: '取消',
 | 
			
		||||
    }).then(() => {
 | 
			
		||||
      this.deleteGoodsService({ spuId, skuId }).then(() => {
 | 
			
		||||
        Toast({ context: this, selector: '#t-toast', message: '商品删除成功' });
 | 
			
		||||
        this.refreshData();
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onSelectAll(event) {
 | 
			
		||||
    const { isAllSelected } = event?.detail ?? {};
 | 
			
		||||
    Toast({
 | 
			
		||||
      context: this,
 | 
			
		||||
      selector: '#t-toast',
 | 
			
		||||
      message: `${isAllSelected ? '取消' : '点击'}了全选按钮`,
 | 
			
		||||
    });
 | 
			
		||||
    // 调用接口改变全选
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onToSettle() {
 | 
			
		||||
    const goodsRequestList = [];
 | 
			
		||||
    this.data.cartGroupData.storeGoods.forEach((store) => {
 | 
			
		||||
      store.promotionGoodsList.forEach((promotion) => {
 | 
			
		||||
        promotion.goodsPromotionList.forEach((m) => {
 | 
			
		||||
          if (m.isSelected == 1) {
 | 
			
		||||
            goodsRequestList.push(m);
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    wx.setStorageSync('order.goodsRequestList', JSON.stringify(goodsRequestList));
 | 
			
		||||
    wx.navigateTo({ url: '/pages/order/order-confirm/index?type=cart' });
 | 
			
		||||
  },
 | 
			
		||||
  onGotoHome() {
 | 
			
		||||
    wx.switchTab({ url: '/pages/home/home' });
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										10
									
								
								mini-program/pages/cart/index.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								mini-program/pages/cart/index.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
{
 | 
			
		||||
  "navigationBarTitleText": "购物车",
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "cart-group": "./components/cart-group/index",
 | 
			
		||||
    "cart-empty": "./components/cart-empty/index",
 | 
			
		||||
    "cart-bar": "./components/cart-bar/index",
 | 
			
		||||
    "t-toast": "tdesign-miniprogram/toast/toast",
 | 
			
		||||
    "t-dialog": "tdesign-miniprogram/dialog/dialog"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								mini-program/pages/cart/index.wxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								mini-program/pages/cart/index.wxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
<!-- 分层购物车 -->
 | 
			
		||||
<block wx:if="{{cartGroupData.isNotEmpty}}">
 | 
			
		||||
  <cart-group
 | 
			
		||||
    store-goods="{{ cartGroupData.storeGoods }}"
 | 
			
		||||
    invalid-good-items="{{ cartGroupData.invalidGoodItems }}"
 | 
			
		||||
    bindselectgoods="onGoodsSelect"
 | 
			
		||||
    bindselectstore="onStoreSelect"
 | 
			
		||||
    bindchangequantity="onQuantityChange"
 | 
			
		||||
    bindgocollect="goCollect"
 | 
			
		||||
    bindgoodsclick="goGoodsDetail"
 | 
			
		||||
    bindclearinvalidgoods="clearInvalidGoods"
 | 
			
		||||
    binddelete="onGoodsDelete"
 | 
			
		||||
  />
 | 
			
		||||
 | 
			
		||||
  <view class="gap" />
 | 
			
		||||
  <!-- 商品小计以及结算按钮 -->
 | 
			
		||||
  <cart-bar
 | 
			
		||||
    is-all-selected="{{cartGroupData.isAllSelected}}"
 | 
			
		||||
    total-amount="{{cartGroupData.totalAmount}}"
 | 
			
		||||
    total-goods-num="{{cartGroupData.selectedGoodsCount}}"
 | 
			
		||||
    total-discount-amount="{{cartGroupData.totalDiscountAmount}}"
 | 
			
		||||
    fixed="{{true}}"
 | 
			
		||||
    bottomHeight="{{112}}"
 | 
			
		||||
    bindhandleSelectAll="onSelectAll"
 | 
			
		||||
    bindhandleToSettle="onToSettle"
 | 
			
		||||
  />
 | 
			
		||||
</block>
 | 
			
		||||
<!-- 购物车空态 -->
 | 
			
		||||
<cart-empty wx:else bind:handleClick="onGotoHome" />
 | 
			
		||||
<t-toast id="t-toast" />
 | 
			
		||||
<t-dialog id="t-dialog" />
 | 
			
		||||
							
								
								
									
										13
									
								
								mini-program/pages/cart/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								mini-program/pages/cart/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
:host {
 | 
			
		||||
  padding-bottom: 100rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.gap {
 | 
			
		||||
  height: 100rpx;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.t-button {
 | 
			
		||||
  --td-button-default-color: #000;
 | 
			
		||||
  --td-button-primary-text-color: #fa4126;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										57
									
								
								mini-program/pages/coupon/components/coupon-card/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								mini-program/pages/coupon/components/coupon-card/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
const statusMap = {
 | 
			
		||||
  default: { text: '去使用', theme: 'primary' },
 | 
			
		||||
  useless: { text: '已使用', theme: 'default' },
 | 
			
		||||
  disabled: { text: '已过期', theme: 'default' },
 | 
			
		||||
};
 | 
			
		||||
Component({
 | 
			
		||||
  options: {
 | 
			
		||||
    addGlobalClass: true,
 | 
			
		||||
    multipleSlots: true, // 在组件定义时的选项中启用多slot支持
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  externalClasses: ['coupon-class'],
 | 
			
		||||
 | 
			
		||||
  properties: {
 | 
			
		||||
    couponDTO: {
 | 
			
		||||
      type: Object,
 | 
			
		||||
      value: {}, // 优惠券数据
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  data: {
 | 
			
		||||
    btnText: '',
 | 
			
		||||
    btnTheme: '',
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  observers: {
 | 
			
		||||
    couponDTO: function (couponDTO) {
 | 
			
		||||
      if (!couponDTO) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      const statusInfo = statusMap[couponDTO.status];
 | 
			
		||||
 | 
			
		||||
      this.setData({
 | 
			
		||||
        btnText: statusInfo.text,
 | 
			
		||||
        btnTheme: statusInfo.theme,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  attached() {},
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    // 跳转到详情页
 | 
			
		||||
    gotoDetail() {
 | 
			
		||||
      wx.navigateTo({
 | 
			
		||||
        url: `/pages/coupon/coupon-detail/index?id=${this.data.couponDTO.key}`,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 跳转到商品列表
 | 
			
		||||
    gotoGoodsList() {
 | 
			
		||||
      wx.navigateTo({
 | 
			
		||||
        url: `/pages/coupon/coupon-activity-goods/index?id=${this.data.couponDTO.key}`,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "ui-coupon-card": "../ui-coupon-card/index",
 | 
			
		||||
    "t-button": "tdesign-miniprogram/button/button"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								mini-program/pages/coupon/components/coupon-card/index.wxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								mini-program/pages/coupon/components/coupon-card/index.wxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
<ui-coupon-card
 | 
			
		||||
  title="{{couponDTO.title || ''}}"
 | 
			
		||||
  type="{{couponDTO.type || ''}}"
 | 
			
		||||
  value="{{couponDTO.value || '0'}}"
 | 
			
		||||
  tag="{{couponDTO.tag || ''}}"
 | 
			
		||||
  desc="{{couponDTO.desc || ''}}"
 | 
			
		||||
  currency="{{couponDTO.currency || ''}}"
 | 
			
		||||
  timeLimit="{{couponDTO.timeLimit || ''}}"
 | 
			
		||||
  status="{{couponDTO.status || ''}}"
 | 
			
		||||
  bind:tap="gotoDetail"
 | 
			
		||||
>
 | 
			
		||||
  <view slot="operator" class="coupon-btn-slot">
 | 
			
		||||
    <t-button
 | 
			
		||||
      t-class="coupon-btn-{{btnTheme}}"
 | 
			
		||||
      theme="{{btnTheme}}"
 | 
			
		||||
      variant="outline"
 | 
			
		||||
      shape="round"
 | 
			
		||||
      size="extra-small"
 | 
			
		||||
      bind:tap="gotoGoodsList"
 | 
			
		||||
      >{{btnText}}
 | 
			
		||||
    </t-button>
 | 
			
		||||
  </view>
 | 
			
		||||
</ui-coupon-card>
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
.coupon-btn-default {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.coupon-btn-primary {
 | 
			
		||||
  --td-button-extra-small-padding-horizontal: 26rpx;
 | 
			
		||||
  --td-button-primary-outline-color: #fa4126;
 | 
			
		||||
  --td-button-primary-outline-border-color: #fa4126;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,17 @@
 | 
			
		||||
Component({
 | 
			
		||||
  data: { icon: 'cart' },
 | 
			
		||||
 | 
			
		||||
  properties: {
 | 
			
		||||
    count: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    goToCart() {
 | 
			
		||||
      wx.switchTab({
 | 
			
		||||
        url: '/pages/cart/index',
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "t-icon": "tdesign-miniprogram/icon/icon"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,14 @@
 | 
			
		||||
<view class="floating-button" bind:tap="goToCart">
 | 
			
		||||
	<view class="floating-inner-container">
 | 
			
		||||
		<t-icon
 | 
			
		||||
		  prefix="wr"
 | 
			
		||||
		  name="{{icon}}"
 | 
			
		||||
		  size="42rpx"
 | 
			
		||||
		  color="#FFFFFF"
 | 
			
		||||
		/>
 | 
			
		||||
	</view>
 | 
			
		||||
	<view class="floating-right-top">
 | 
			
		||||
		{{count}}
 | 
			
		||||
	</view>
 | 
			
		||||
</view>
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,30 @@
 | 
			
		||||
.floating-button {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  right: 20rpx;
 | 
			
		||||
  bottom: 108rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.floating-button .floating-inner-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  height: 96rpx;
 | 
			
		||||
  width: 96rpx;
 | 
			
		||||
  background-color: rgba(0, 0, 0, 0.8);
 | 
			
		||||
  opacity: 0.7;
 | 
			
		||||
  border-radius: 48rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.floating-button .floating-right-top {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  right: 0rpx;
 | 
			
		||||
  top: 0rpx;
 | 
			
		||||
  height: 28rpx;
 | 
			
		||||
  background: #fa4126;
 | 
			
		||||
  border-radius: 64rpx;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  font-size: 22rpx;
 | 
			
		||||
  line-height: 28rpx;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  padding: 0 8rpx;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										87
									
								
								mini-program/pages/coupon/components/ui-coupon-card/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								mini-program/pages/coupon/components/ui-coupon-card/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,87 @@
 | 
			
		||||
Component({
 | 
			
		||||
  options: {
 | 
			
		||||
    addGlobalClass: true,
 | 
			
		||||
    multipleSlots: true,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  externalClasses: ['coupon-class'],
 | 
			
		||||
 | 
			
		||||
  properties: {
 | 
			
		||||
    mask: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      value: false, // 是否添加遮罩
 | 
			
		||||
    },
 | 
			
		||||
    superposable: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      value: false, // 是否可叠加
 | 
			
		||||
    },
 | 
			
		||||
    type: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '', // 优惠券类型:CouponType
 | 
			
		||||
    },
 | 
			
		||||
    value: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '', // 优惠金额
 | 
			
		||||
    },
 | 
			
		||||
    tag: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '', // 优惠标签,优惠券名字标签,img
 | 
			
		||||
    },
 | 
			
		||||
    desc: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '', // 优惠金额描述,金额下方
 | 
			
		||||
    },
 | 
			
		||||
    title: {
 | 
			
		||||
      type: String, // 优惠券名称
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
    timeLimit: {
 | 
			
		||||
      type: String, // 优惠券时限
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
    ruleDesc: {
 | 
			
		||||
      type: String, // 优惠券适用规则描述
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
    currency: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '¥', // 优惠货币
 | 
			
		||||
    },
 | 
			
		||||
    status: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: 'default',
 | 
			
		||||
    },
 | 
			
		||||
    image: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  data: {
 | 
			
		||||
    CouponType: {
 | 
			
		||||
      MJ_COUPON: 1,
 | 
			
		||||
      ZK_COUPON: 2,
 | 
			
		||||
      MJF_COUPON: 3,
 | 
			
		||||
      GIFT_COUPON: 4,
 | 
			
		||||
    },
 | 
			
		||||
    theme: 'primary',
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  observers: {
 | 
			
		||||
    status: function (value) {
 | 
			
		||||
      let theme = 'primary';
 | 
			
		||||
      // 已过期或已使用的券 颜色置灰
 | 
			
		||||
      if (value === 'useless' || value === 'disabled') {
 | 
			
		||||
        theme = 'weak';
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.setData({ theme });
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  attached() {
 | 
			
		||||
    this.setData({
 | 
			
		||||
      color: `color${this.properties.colorStyle}`,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "t-icon": "tdesign-miniprogram/icon/icon",
 | 
			
		||||
    "t-image": "/components/webp-image/index"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,54 @@
 | 
			
		||||
<wxs module="tools">
 | 
			
		||||
	function isBigValue(value) {
 | 
			
		||||
	var values = (value + '').split('.');
 | 
			
		||||
	if (values[1] && values[0].length >= 3) return true;
 | 
			
		||||
	else return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function getBigValues(value) {
 | 
			
		||||
	return value.split('.');
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	module.exports = { isBigValue: isBigValue, getBigValues: getBigValues };
 | 
			
		||||
</wxs>
 | 
			
		||||
<view class="wr-coupon coupon-class theme-{{theme}}">
 | 
			
		||||
	<view class="wr-coupon__left">
 | 
			
		||||
		<view wx:if="{{type == CouponType.ZK_COUPON || type === CouponType.MERCHANT_ZK_COUPON}}">
 | 
			
		||||
			<text class="wr-coupon__left--value">{{value}}</text>
 | 
			
		||||
			<text class="wr-coupon__left--unit">折</text>
 | 
			
		||||
			<view class="wr-coupon__left--desc">{{desc}}</view>
 | 
			
		||||
		</view>
 | 
			
		||||
		<view wx:if="{{type == CouponType.MJ_COUPON || type === CouponType.MERCHANT_MJ_COUPON}}">
 | 
			
		||||
			<text class="wr-coupon__left--value" wx:if="{{tools.isBigValue(value)}}">
 | 
			
		||||
				<text class="wr-coupon__left--value-int">{{tools.getBigValues(value)[0]}}</text>
 | 
			
		||||
				<text class="wr-coupon__left--value-decimal">.{{tools.getBigValues(value)[1]}}</text>
 | 
			
		||||
			</text>
 | 
			
		||||
			<text class="wr-coupon__left--value" wx:else>{{value / 100}}</text>
 | 
			
		||||
			<text class="wr-coupon__left--unit">元</text>
 | 
			
		||||
			<view class="wr-coupon__left--desc">{{desc}}</view>
 | 
			
		||||
		</view>
 | 
			
		||||
		<view wx:if="{{type === CouponType.MJF_COUPON || type === CouponType.MYF_COUPON}}">
 | 
			
		||||
			<text class="wr-coupon__left--value" style="font-family: PingFang SC;font-size: 44rpx">免邮</text>
 | 
			
		||||
			<view class="wr-coupon__left--desc">{{desc}}</view>
 | 
			
		||||
		</view>
 | 
			
		||||
		<view wx:if="{{type == CouponType.GIFT_COUPON}}">
 | 
			
		||||
			<t-image t-class="wr-coupon__left--image" src="{{image}}" mode="aspectFill" />
 | 
			
		||||
		</view>
 | 
			
		||||
	</view>
 | 
			
		||||
	<view class="wr-coupon__right">
 | 
			
		||||
		<view class="wr-coupon__right--title">
 | 
			
		||||
			<text class="coupon-title">{{title}}</text>
 | 
			
		||||
			<view class="coupon-time">{{timeLimit}}</view>
 | 
			
		||||
			<view class="coupon-desc">
 | 
			
		||||
				<view wx:if="{{ruleDesc}}">{{ruleDesc}}</view>
 | 
			
		||||
			</view>
 | 
			
		||||
		</view>
 | 
			
		||||
		<view class="wr-coupon__right--oper">
 | 
			
		||||
			<slot name="operator" />
 | 
			
		||||
		</view>
 | 
			
		||||
	</view>
 | 
			
		||||
	<view wx:if="{{status === 'useless' || status === 'disabled'}}" class="wr-coupon__seal seal-{{status}}}" />
 | 
			
		||||
	<view wx:if="{{mask}}" class="wr-coupon__mask" />
 | 
			
		||||
	<view wx:if="{{superposable}}" class="wr-coupon__tag">可叠加</view>
 | 
			
		||||
</view>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										147
									
								
								mini-program/pages/coupon/components/ui-coupon-card/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								mini-program/pages/coupon/components/ui-coupon-card/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,147 @@
 | 
			
		||||
.wr-coupon {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  background-image: url('https://cdn-we-retail.ym.tencent.com/miniapp/coupon/coupon-bg-nocorners.png');
 | 
			
		||||
  background-size: 100% 100%;
 | 
			
		||||
  background-repeat: no-repeat;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  margin-bottom: 24rpx;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
.theme-weak.wr-coupon {
 | 
			
		||||
  background-image: url('https://cdn-we-retail.ym.tencent.com/miniapp/coupon/coupon-bg-grey2.png');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.wr-coupon__left {
 | 
			
		||||
  width: 200rpx;
 | 
			
		||||
  height: 180rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
.theme-weak .wr-coupon__left {
 | 
			
		||||
  color: #333;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.wr-coupon__left--value {
 | 
			
		||||
  font-size: 64rpx;
 | 
			
		||||
  line-height: 88rpx;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  font-family: 'DIN Alternate', cursive;
 | 
			
		||||
}
 | 
			
		||||
.wr-coupon__left--value-int {
 | 
			
		||||
  font-size: 48rpx;
 | 
			
		||||
  line-height: 88rpx;
 | 
			
		||||
}
 | 
			
		||||
.wr-coupon__left--value-decimal {
 | 
			
		||||
  font-size: 36rpx;
 | 
			
		||||
  line-height: 48rpx;
 | 
			
		||||
}
 | 
			
		||||
.wr-coupon__left--image {
 | 
			
		||||
  width: 128rpx;
 | 
			
		||||
  height: 128rpx;
 | 
			
		||||
  border-radius: 8px;
 | 
			
		||||
  margin-top: 30rpx;
 | 
			
		||||
}
 | 
			
		||||
.wr-coupon__left--unit {
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  line-height: 32rpx;
 | 
			
		||||
}
 | 
			
		||||
.wr-coupon__left--desc {
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  line-height: 32rpx;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.theme-weak .wr-coupon__left--desc {
 | 
			
		||||
  color: #333;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.wr-coupon__right {
 | 
			
		||||
  flex-grow: 1;
 | 
			
		||||
  padding: 0 20rpx;
 | 
			
		||||
  height: 180rpx;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
.wr-coupon__right--title {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  -webkit-display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: flex-start;
 | 
			
		||||
  color: #999999;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  flex: 1;
 | 
			
		||||
}
 | 
			
		||||
.wr-coupon__right--title .coupon-title {
 | 
			
		||||
  max-width: 320rpx;
 | 
			
		||||
  color: #333333;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  line-height: 40rpx;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  display: -webkit-box;
 | 
			
		||||
  -webkit-line-clamp: 1;
 | 
			
		||||
  -webkit-box-orient: vertical;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  white-space: normal;
 | 
			
		||||
}
 | 
			
		||||
.wr-coupon__right--title .coupon-time {
 | 
			
		||||
  margin-top: 16rpx;
 | 
			
		||||
  /* //   letter-spacing: -0.05em; */
 | 
			
		||||
}
 | 
			
		||||
.wr-coupon__right--title .coupon-desc {
 | 
			
		||||
  margin-top: 8rpx;
 | 
			
		||||
}
 | 
			
		||||
.wr-coupon__right--title .coupon-arrow {
 | 
			
		||||
  font-size: 22rpx;
 | 
			
		||||
}
 | 
			
		||||
.wr-coupon__right--oper {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
.wr-coupon__mask {
 | 
			
		||||
  width: 702rpx;
 | 
			
		||||
  height: 182rpx;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  background-color: #ffffff;
 | 
			
		||||
  opacity: 0.5;
 | 
			
		||||
}
 | 
			
		||||
.wr-coupon__tag {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 8px;
 | 
			
		||||
  right: -24rpx;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  width: 106rpx;
 | 
			
		||||
  height: 28rpx;
 | 
			
		||||
  opacity: 0.9;
 | 
			
		||||
  font-size: 20rpx;
 | 
			
		||||
  line-height: 28rpx;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
  border: 0.5px solid #fa4126;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  transform: rotate(45deg);
 | 
			
		||||
}
 | 
			
		||||
.wr-coupon__seal {
 | 
			
		||||
  width: 128rpx;
 | 
			
		||||
  height: 128rpx;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  background-size: 100% 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.wr-coupon__seal.seal-useless {
 | 
			
		||||
  background-image: url('https://cdn-we-retail.ym.tencent.com/miniapp/coupon/seal-used.png');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.wr-coupon__seal.seal-disabled {
 | 
			
		||||
  background-image: url('https://cdn-we-retail.ym.tencent.com/miniapp/coupon/coupon-expired.png');
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										78
									
								
								mini-program/pages/coupon/coupon-activity-goods/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								mini-program/pages/coupon/coupon-activity-goods/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
import { fetchCouponDetail } from '../../../services/coupon/index';
 | 
			
		||||
import { fetchGoodsList } from '../../../services/good/fetchGoods';
 | 
			
		||||
import Toast from 'tdesign-miniprogram/toast/index';
 | 
			
		||||
 | 
			
		||||
Page({
 | 
			
		||||
  data: {
 | 
			
		||||
    goods: [],
 | 
			
		||||
    detail: {},
 | 
			
		||||
    couponTypeDesc: '',
 | 
			
		||||
    showStoreInfoList: false,
 | 
			
		||||
    cartNum: 2,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  id: '',
 | 
			
		||||
 | 
			
		||||
  onLoad(query) {
 | 
			
		||||
    const id = parseInt(query.id);
 | 
			
		||||
    this.id = id;
 | 
			
		||||
 | 
			
		||||
    this.getCouponDetail(id);
 | 
			
		||||
    this.getGoodsList(id);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  getCouponDetail(id) {
 | 
			
		||||
    fetchCouponDetail(id).then(({ detail }) => {
 | 
			
		||||
      this.setData({ detail });
 | 
			
		||||
      if (detail.type === 2) {
 | 
			
		||||
        if (detail.base > 0) {
 | 
			
		||||
          this.setData({
 | 
			
		||||
            couponTypeDesc: `满${detail.base / 100}元${detail.value}折`,
 | 
			
		||||
          });
 | 
			
		||||
        } else {
 | 
			
		||||
          this.setData({ couponTypeDesc: `${detail.value}折` });
 | 
			
		||||
        }
 | 
			
		||||
      } else if (detail.type === 1) {
 | 
			
		||||
        if (detail.base > 0) {
 | 
			
		||||
          this.setData({
 | 
			
		||||
            couponTypeDesc: `满${detail.base / 100}元减${detail.value / 100}元`,
 | 
			
		||||
          });
 | 
			
		||||
        } else {
 | 
			
		||||
          this.setData({ couponTypeDesc: `减${detail.value / 100}元` });
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  getGoodsList(id) {
 | 
			
		||||
    fetchGoodsList(id).then((goods) => {
 | 
			
		||||
      this.setData({ goods });
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  openStoreList() {
 | 
			
		||||
    this.setData({
 | 
			
		||||
      showStoreInfoList: true,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  closeStoreList() {
 | 
			
		||||
    this.setData({
 | 
			
		||||
      showStoreInfoList: false,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  goodClickHandle(e) {
 | 
			
		||||
    const { index } = e.detail;
 | 
			
		||||
    const { spuId } = this.data.goods[index];
 | 
			
		||||
    wx.navigateTo({ url: `/pages/goods/details/index?spuId=${spuId}` });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  cartClickHandle() {
 | 
			
		||||
    Toast({
 | 
			
		||||
      context: this,
 | 
			
		||||
      selector: '#t-toast',
 | 
			
		||||
      message: '点击加入购物车',
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										10
									
								
								mini-program/pages/coupon/coupon-activity-goods/index.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								mini-program/pages/coupon/coupon-activity-goods/index.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
{
 | 
			
		||||
  "navigationBarTitleText": "活动商品",
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "t-icon": "tdesign-miniprogram/icon/icon",
 | 
			
		||||
    "t-popup": "tdesign-miniprogram/popup/popup",
 | 
			
		||||
    "t-toast": "tdesign-miniprogram/toast/toast",
 | 
			
		||||
    "goods-list": "/components/goods-list/index",
 | 
			
		||||
    "floating-button": "../components/floating-button/index"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								mini-program/pages/coupon/coupon-activity-goods/index.wxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								mini-program/pages/coupon/coupon-activity-goods/index.wxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
<view class="coupon-page-container">
 | 
			
		||||
  <view class="notice-bar-content">
 | 
			
		||||
    <view class="notice-bar-text">
 | 
			
		||||
      以下商品可使用
 | 
			
		||||
      <text class="height-light">{{couponTypeDesc}}</text>
 | 
			
		||||
      优惠券
 | 
			
		||||
    </view>
 | 
			
		||||
    <t-icon name="help-circle" size="32rpx" color="#AAAAAA" bind:tap="openStoreList" />
 | 
			
		||||
  </view>
 | 
			
		||||
  <view class="goods-list-container">
 | 
			
		||||
    <goods-list
 | 
			
		||||
      wr-class="goods-list-wrap"
 | 
			
		||||
      goodsList="{{goods}}"
 | 
			
		||||
      bind:click="goodClickHandle"
 | 
			
		||||
      bind:addcart="cartClickHandle"
 | 
			
		||||
    />
 | 
			
		||||
  </view>
 | 
			
		||||
  <floating-button count="{{cartNum}}" />
 | 
			
		||||
  <t-popup visible="{{showStoreInfoList}}" placement="bottom" bind:visible-change="closeStoreList">
 | 
			
		||||
    <t-icon slot="closeBtn" name="close" size="40rpx" bind:tap="closeStoreList" />
 | 
			
		||||
    <view class="popup-content-wrap">
 | 
			
		||||
      <view class="popup-content-title"> 规则详情 </view>
 | 
			
		||||
      <view class="desc-group-wrap">
 | 
			
		||||
        <view wx:if="{{detail && detail.timeLimit}}" class="item-wrap">
 | 
			
		||||
          <view class="item-title">优惠券有效时间</view>
 | 
			
		||||
          <view class="item-label">{{detail.timeLimit}}</view>
 | 
			
		||||
        </view>
 | 
			
		||||
        <view wx:if="{{detail && detail.desc}}" class="item-wrap">
 | 
			
		||||
          <view class="item-title">优惠券说明</view>
 | 
			
		||||
          <view class="item-label">{{detail.desc}}</view>
 | 
			
		||||
        </view>
 | 
			
		||||
        <view wx:if="{{detail && detail.useNotes}}" class="item-wrap">
 | 
			
		||||
          <view class="item-title">使用须知</view>
 | 
			
		||||
          <view class="item-label">{{detail.useNotes}}</view>
 | 
			
		||||
        </view>
 | 
			
		||||
      </view>
 | 
			
		||||
    </view>
 | 
			
		||||
  </t-popup>
 | 
			
		||||
</view>
 | 
			
		||||
<t-toast id="t-toast" />
 | 
			
		||||
							
								
								
									
										69
									
								
								mini-program/pages/coupon/coupon-activity-goods/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								mini-program/pages/coupon/coupon-activity-goods/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
			
		||||
page {
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.coupon-page-container .notice-bar-content {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: row;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  padding: 8rpx 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.coupon-page-container .notice-bar-text {
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  line-height: 36rpx;
 | 
			
		||||
  font-weight: 400;
 | 
			
		||||
  color: #666666;
 | 
			
		||||
  margin-left: 24rpx;
 | 
			
		||||
  margin-right: 12rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.coupon-page-container .notice-bar-text .height-light {
 | 
			
		||||
  color: #fa550f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.coupon-page-container .popup-content-wrap {
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  border-top-left-radius: 20rpx;
 | 
			
		||||
  border-top-right-radius: 20rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.coupon-page-container .popup-content-title {
 | 
			
		||||
  font-size: 32rpx;
 | 
			
		||||
  color: #333;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  height: 104rpx;
 | 
			
		||||
  line-height: 104rpx;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.coupon-page-container .desc-group-wrap {
 | 
			
		||||
  padding-bottom: env(safe-area-inset-bottom);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.coupon-page-container .desc-group-wrap .item-wrap {
 | 
			
		||||
  margin: 0 30rpx 30rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.coupon-page-container .desc-group-wrap .item-title {
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  color: #333;
 | 
			
		||||
  font-weight: 500;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.coupon-page-container .desc-group-wrap .item-label {
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  color: #666;
 | 
			
		||||
  margin-top: 12rpx;
 | 
			
		||||
  white-space: pre-line;
 | 
			
		||||
  word-break: break-all;
 | 
			
		||||
  line-height: 34rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.coupon-page-container .goods-list-container {
 | 
			
		||||
  margin: 0 24rpx 24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.coupon-page-container .goods-list-wrap {
 | 
			
		||||
  background: #f5f5f5 !important;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								mini-program/pages/coupon/coupon-detail/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								mini-program/pages/coupon/coupon-detail/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
import { fetchCouponDetail } from '../../../services/coupon/index';
 | 
			
		||||
 | 
			
		||||
Page({
 | 
			
		||||
  data: {
 | 
			
		||||
    detail: null,
 | 
			
		||||
    storeInfoList: [],
 | 
			
		||||
    storeInfoStr: '',
 | 
			
		||||
    showStoreInfoList: false,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  id: '',
 | 
			
		||||
 | 
			
		||||
  onLoad(query) {
 | 
			
		||||
    const id = parseInt(query.id);
 | 
			
		||||
    this.id = id;
 | 
			
		||||
    this.getGoodsList(id);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  getGoodsList(id) {
 | 
			
		||||
    fetchCouponDetail(id).then(({ detail }) => {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        detail,
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  navGoodListHandle() {
 | 
			
		||||
    wx.navigateTo({
 | 
			
		||||
      url: `/pages/coupon/coupon-activity-goods/index?id=${this.id}`,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										10
									
								
								mini-program/pages/coupon/coupon-detail/index.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								mini-program/pages/coupon/coupon-detail/index.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
{
 | 
			
		||||
  "navigationBarTitleText": "优惠券详情",
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "coupon-card": "../components/coupon-card/index",
 | 
			
		||||
    "t-cell": "tdesign-miniprogram/cell/cell",
 | 
			
		||||
    "t-cell-group": "tdesign-miniprogram/cell-group/cell-group",
 | 
			
		||||
    "t-button": "tdesign-miniprogram/button/button",
 | 
			
		||||
    "t-icon": "tdesign-miniprogram/icon/icon"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								mini-program/pages/coupon/coupon-detail/index.wxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								mini-program/pages/coupon/coupon-detail/index.wxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
<!-- 优惠券 -->
 | 
			
		||||
<view class="coupon-card-wrap">
 | 
			
		||||
  <coupon-card couponDTO="{{detail}}" />
 | 
			
		||||
</view>
 | 
			
		||||
<!-- 说明 -->
 | 
			
		||||
<view class="desc-wrap">
 | 
			
		||||
  <t-cell-group t-class="desc-group-wrap">
 | 
			
		||||
    <t-cell
 | 
			
		||||
      wx:if="{{detail && detail.desc}}"
 | 
			
		||||
      t-class="t-class-cell"
 | 
			
		||||
      t-class-title="t-class-title"
 | 
			
		||||
      t-class-note="t-class-note"
 | 
			
		||||
      title="规则说明"
 | 
			
		||||
      note="{{detail && detail.desc}}"
 | 
			
		||||
    />
 | 
			
		||||
    <t-cell
 | 
			
		||||
      wx:if="{{detail && detail.timeLimit}}"
 | 
			
		||||
      t-class="t-class-cell"
 | 
			
		||||
      t-class-title="t-class-title"
 | 
			
		||||
      t-class-note="t-class-note"
 | 
			
		||||
      title="有效时间"
 | 
			
		||||
      note="{{detail && detail.timeLimit}}"
 | 
			
		||||
    />
 | 
			
		||||
    <t-cell
 | 
			
		||||
      wx:if="{{detail && detail.storeAdapt}}"
 | 
			
		||||
      t-class="t-class-cell"
 | 
			
		||||
      t-class-title="t-class-title"
 | 
			
		||||
      t-class-note="t-class-note"
 | 
			
		||||
      title="适用范围"
 | 
			
		||||
      note="{{detail && detail.storeAdapt}}"
 | 
			
		||||
    />
 | 
			
		||||
    <t-cell
 | 
			
		||||
      wx:if="{{detail && detail.useNotes}}"
 | 
			
		||||
      t-class="t-class-cell"
 | 
			
		||||
      t-class-title="t-class-title"
 | 
			
		||||
      t-class-note="t-class-note"
 | 
			
		||||
      title="使用须知"
 | 
			
		||||
      note="{{detail && detail.useNotes}}"
 | 
			
		||||
    />
 | 
			
		||||
  </t-cell-group>
 | 
			
		||||
  <!-- 查看可用商品 -->
 | 
			
		||||
  <view class="button-wrap">
 | 
			
		||||
    <t-button shape="round" block bindtap="navGoodListHandle"> 查看可用商品 </t-button>
 | 
			
		||||
  </view>
 | 
			
		||||
</view>
 | 
			
		||||
							
								
								
									
										91
									
								
								mini-program/pages/coupon/coupon-detail/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								mini-program/pages/coupon/coupon-detail/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,91 @@
 | 
			
		||||
page {
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.coupon-card-wrap {
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  padding: 32rpx 32rpx 1rpx;
 | 
			
		||||
}
 | 
			
		||||
.desc-wrap {
 | 
			
		||||
  margin-top: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
.desc-wrap .button-wrap {
 | 
			
		||||
  margin: 50rpx 32rpx 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.desc-group-wrap .t-class-cell {
 | 
			
		||||
  align-items: flex-start;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.desc-group-wrap .t-class-title {
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  width: 140rpx;
 | 
			
		||||
  flex: none;
 | 
			
		||||
  color: #888;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.desc-group-wrap .t-class-note {
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  word-break: break-all;
 | 
			
		||||
  white-space: pre-line;
 | 
			
		||||
  justify-content: flex-start;
 | 
			
		||||
  color: #333;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.desc-group-wrap {
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
 | 
			
		||||
  --cell-label-font-size: 26rpx;
 | 
			
		||||
  --cell-label-line-height: 36rpx;
 | 
			
		||||
  --cell-label-color: #999;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.desc-group-wrap.in-popup {
 | 
			
		||||
  border-radius: 0;
 | 
			
		||||
  overflow: auto;
 | 
			
		||||
  max-height: 828rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.desc-group-wrap .wr-cell__title {
 | 
			
		||||
  color: #333;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* .desc-group-wrap .max-width-cell {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
} */
 | 
			
		||||
 | 
			
		||||
/* .desc-group-wrap .signal-line-label {
 | 
			
		||||
  word-break: keep-all;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  text-overflow: ellipsis;
 | 
			
		||||
}
 | 
			
		||||
.desc-group-wrap .multi-line-label {
 | 
			
		||||
  word-break: break-all;
 | 
			
		||||
  white-space: pre-line;
 | 
			
		||||
} */
 | 
			
		||||
 | 
			
		||||
.popup-content-wrap {
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  border-top-left-radius: 20rpx;
 | 
			
		||||
  border-top-right-radius: 20rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-content-title {
 | 
			
		||||
  font-size: 32rpx;
 | 
			
		||||
  color: #333;
 | 
			
		||||
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  height: 104rpx;
 | 
			
		||||
  line-height: 104rpx;
 | 
			
		||||
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-content-title .close-icon {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 24rpx;
 | 
			
		||||
  right: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										77
									
								
								mini-program/pages/coupon/coupon-list/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								mini-program/pages/coupon/coupon-list/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
			
		||||
import { fetchCouponList } from '../../../services/coupon/index';
 | 
			
		||||
 | 
			
		||||
Page({
 | 
			
		||||
  data: {
 | 
			
		||||
    status: 0,
 | 
			
		||||
    list: [
 | 
			
		||||
      {
 | 
			
		||||
        text: '可使用',
 | 
			
		||||
        key: 0,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        text: '已使用',
 | 
			
		||||
        key: 1,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        text: '已失效',
 | 
			
		||||
        key: 2,
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
 | 
			
		||||
    couponList: [],
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onLoad() {
 | 
			
		||||
    this.init();
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  init() {
 | 
			
		||||
    this.fetchList();
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  fetchList(status = this.data.status) {
 | 
			
		||||
    let statusInFetch = '';
 | 
			
		||||
    switch (Number(status)) {
 | 
			
		||||
      case 0: {
 | 
			
		||||
        statusInFetch = 'default';
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case 1: {
 | 
			
		||||
        statusInFetch = 'useless';
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case 2: {
 | 
			
		||||
        statusInFetch = 'disabled';
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      default: {
 | 
			
		||||
        throw new Error(`unknown fetchStatus: ${statusInFetch}`);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    fetchCouponList(statusInFetch).then((couponList) => {
 | 
			
		||||
      this.setData({ couponList });
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  tabChange(e) {
 | 
			
		||||
    const { value } = e.detail;
 | 
			
		||||
 | 
			
		||||
    this.setData({ status: value });
 | 
			
		||||
    this.fetchList(value);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  goCouponCenterHandle() {
 | 
			
		||||
    wx.showToast({ title: '去领券中心', icon: 'none' });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onPullDownRefresh_() {
 | 
			
		||||
    this.setData(
 | 
			
		||||
      {
 | 
			
		||||
        couponList: [],
 | 
			
		||||
      },
 | 
			
		||||
      () => {
 | 
			
		||||
        this.fetchList();
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										10
									
								
								mini-program/pages/coupon/coupon-list/index.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								mini-program/pages/coupon/coupon-list/index.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
{
 | 
			
		||||
  "navigationBarTitleText": "优惠券",
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "t-pull-down-refresh": "tdesign-miniprogram/pull-down-refresh/pull-down-refresh",
 | 
			
		||||
    "t-tabs": "tdesign-miniprogram/tabs/tabs",
 | 
			
		||||
    "t-tab-panel": "tdesign-miniprogram/tab-panel/tab-panel",
 | 
			
		||||
    "t-icon": "tdesign-miniprogram/icon/icon",
 | 
			
		||||
    "coupon-card": "../components/coupon-card/index"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								mini-program/pages/coupon/coupon-list/index.wxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								mini-program/pages/coupon/coupon-list/index.wxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
<t-tabs
 | 
			
		||||
  defaultValue="{{status}}"
 | 
			
		||||
  bind:change="tabChange"
 | 
			
		||||
  tabList="{{list}}"
 | 
			
		||||
  t-class="tabs-external__inner"
 | 
			
		||||
	t-class-item="tabs-external__item"
 | 
			
		||||
  t-class-active="tabs-external__active"
 | 
			
		||||
  t-class-track="tabs-external__track"
 | 
			
		||||
>
 | 
			
		||||
	<t-tab-panel
 | 
			
		||||
	  wx:for="{{list}}"
 | 
			
		||||
	  wx:for-index="index"
 | 
			
		||||
	  wx:for-item="tab"
 | 
			
		||||
	  wx:key="key"
 | 
			
		||||
	  label="{{tab.text}}"
 | 
			
		||||
	  value="{{tab.key}}"
 | 
			
		||||
	/>
 | 
			
		||||
</t-tabs>
 | 
			
		||||
<view class="coupon-list-wrap">
 | 
			
		||||
	<t-pull-down-refresh
 | 
			
		||||
	  t-class-indicator="t-class-indicator"
 | 
			
		||||
	  id="t-pull-down-refresh"
 | 
			
		||||
	  bind:refresh="onPullDownRefresh_"
 | 
			
		||||
	  background="#fff"
 | 
			
		||||
	>
 | 
			
		||||
		<view class="coupon-list-item" wx:for="{{couponList}}" wx:key="key">
 | 
			
		||||
			<coupon-card couponDTO="{{item}}" />
 | 
			
		||||
		</view>
 | 
			
		||||
	</t-pull-down-refresh>
 | 
			
		||||
	<view class="center-entry">
 | 
			
		||||
		<view class="center-entry-btn" bind:tap="goCouponCenterHandle">
 | 
			
		||||
			<view>领券中心</view>
 | 
			
		||||
			<t-icon
 | 
			
		||||
			  name="chevron-right"
 | 
			
		||||
			  color="#fa4126"
 | 
			
		||||
			  size="40rpx"
 | 
			
		||||
			  style="line-height: 28rpx;"
 | 
			
		||||
			/>
 | 
			
		||||
		</view>
 | 
			
		||||
	</view>
 | 
			
		||||
</view>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										78
									
								
								mini-program/pages/coupon/coupon-list/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								mini-program/pages/coupon/coupon-list/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
page {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tabs-external__inner {
 | 
			
		||||
  height: 88rpx;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  line-height: 88rpx;
 | 
			
		||||
  z-index: 100;
 | 
			
		||||
}
 | 
			
		||||
.tabs-external__inner {
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  color: #333333;
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  width: 100vw;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tabs-external__inner .tabs-external__track {
 | 
			
		||||
  background: #fa4126 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tabs-external__inner .tabs-external__item {
 | 
			
		||||
  color: #666;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tabs-external__inner .tabs-external__active {
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  color: #fa4126 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tabs-external__inner.order-nav .order-nav-item .bottom-line {
 | 
			
		||||
  bottom: 12rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.coupon-list-wrap {
 | 
			
		||||
  margin-top: 32rpx;
 | 
			
		||||
  margin-left: 32rpx;
 | 
			
		||||
  margin-right: 32rpx;
 | 
			
		||||
  overflow-y: auto;
 | 
			
		||||
  padding-bottom: 100rpx;
 | 
			
		||||
  padding-bottom: calc(constant(safe-area-inset-top) + 100rpx);
 | 
			
		||||
  padding-bottom: calc(env(safe-area-inset-bottom) + 100rpx);
 | 
			
		||||
  -webkit-overflow-scrolling: touch;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.center-entry {
 | 
			
		||||
  box-sizing: content-box;
 | 
			
		||||
  border-top: 1rpx solid #dce0e4;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  height: 100rpx;
 | 
			
		||||
  padding-bottom: 0;
 | 
			
		||||
  padding-bottom: constant(safe-area-inset-top);
 | 
			
		||||
  padding-bottom: env(safe-area-inset-bottom);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.center-entry-btn {
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  line-height: 100rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  height: 100rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.coupon-list-wrap .t-pull-down-refresh__bar {
 | 
			
		||||
  background: #fff !important;
 | 
			
		||||
}
 | 
			
		||||
.t-class-indicator {
 | 
			
		||||
  color: #b9b9b9 !important;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,95 @@
 | 
			
		||||
# Sidebar 侧边导航
 | 
			
		||||
 | 
			
		||||
### 引入
 | 
			
		||||
 | 
			
		||||
全局引入,在miniprogram根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// app.json 或 index.json
 | 
			
		||||
"usingComponents": {
 | 
			
		||||
  "wr-sidebar": "path/to/components/goods-category/wr-sidebar/index",
 | 
			
		||||
  "wr-sidebar-item": "path/to/component/goods-category/wr-sidebar/wr-sidebar-item/index"
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 代码演示
 | 
			
		||||
 | 
			
		||||
### 基础用法
 | 
			
		||||
 | 
			
		||||
通过在`wr-sidebar`上设置`activeKey`属性来控制选中项
 | 
			
		||||
 | 
			
		||||
```html
 | 
			
		||||
<wr-sidebar active-key="{{ activeKey }}" bind:change="onChange">
 | 
			
		||||
  <wr-sidebar-item title="标签名称" />
 | 
			
		||||
  <wr-sidebar-item title="标签名称" />
 | 
			
		||||
  <wr-sidebar-item title="标签名称" />
 | 
			
		||||
</wr-sidebar>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
``` javascript
 | 
			
		||||
Page({
 | 
			
		||||
  data: {
 | 
			
		||||
    activeKey: 0
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onChange(event) {
 | 
			
		||||
    wx.showToast({
 | 
			
		||||
      icon: 'none',
 | 
			
		||||
      title: `切换至第${event.detail}项`
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 提示气泡(暂未实现)
 | 
			
		||||
 | 
			
		||||
设置`dot`属性后,会在右上角展示一个小红点。设置`info`属性后,会在右上角展示相应的徽标
 | 
			
		||||
 | 
			
		||||
```html
 | 
			
		||||
<wr-sidebar active-key="{{ activeKey }}">
 | 
			
		||||
  <wr-sidebar-item title="标签名称" dot />
 | 
			
		||||
  <wr-sidebar-item title="标签名称" info="5" />
 | 
			
		||||
  <wr-sidebar-item title="标签名称" info="99+" />
 | 
			
		||||
</wr-sidebar>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## API
 | 
			
		||||
 | 
			
		||||
### Sidebar Props
 | 
			
		||||
 | 
			
		||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
 | 
			
		||||
|-----------|-----------|-----------|-------------|-------------|
 | 
			
		||||
| activeKey | 选中项的索引 | *string \| number* | `0` | - |
 | 
			
		||||
 | 
			
		||||
### Sidebar Event
 | 
			
		||||
 | 
			
		||||
| 事件名 | 说明 | 参数 |
 | 
			
		||||
|------|------|------|
 | 
			
		||||
| change | 切换选项时触发 | 当前选中选项的索引 |
 | 
			
		||||
 | 
			
		||||
### Sidebar 外部样式类
 | 
			
		||||
 | 
			
		||||
| 类名 | 说明 |
 | 
			
		||||
|-----------|-----------|
 | 
			
		||||
| custom-class | 根节点样式类 |
 | 
			
		||||
 | 
			
		||||
### SidebarItem Props
 | 
			
		||||
 | 
			
		||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
 | 
			
		||||
|-----------|-----------|-----------|-------------|-------------|
 | 
			
		||||
| title | 内容 | *string* | `''` | - |
 | 
			
		||||
| disabled | 是否禁用 | | *boolean* | `false` | - |
 | 
			
		||||
| dot | 是否显示右上角小红点 | *boolean* | `false` | - |
 | 
			
		||||
| info | 提示消息 | *string \| number* | `''` | - |
 | 
			
		||||
 | 
			
		||||
### SidebarItem Event
 | 
			
		||||
 | 
			
		||||
| 事件名 | 说明 | 参数 |
 | 
			
		||||
|------|------|------|
 | 
			
		||||
| click | 点击徽章时触发 | 当前徽章的索引 |
 | 
			
		||||
 | 
			
		||||
### SidebarItem 外部样式类
 | 
			
		||||
 | 
			
		||||
| 类名 | 说明 |
 | 
			
		||||
|-----------|-----------|
 | 
			
		||||
| custom-class | 根节点样式类 |
 | 
			
		||||
@@ -0,0 +1,51 @@
 | 
			
		||||
Component({
 | 
			
		||||
  relations: {
 | 
			
		||||
    '../../c-sidebar/index': {
 | 
			
		||||
      type: 'ancestor',
 | 
			
		||||
      linked(target) {
 | 
			
		||||
        this.parent = target;
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  externalClasses: ['custom-class'],
 | 
			
		||||
  properties: {
 | 
			
		||||
    title: String,
 | 
			
		||||
    disabled: Boolean,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  data: {
 | 
			
		||||
    topRightRadius: false,
 | 
			
		||||
    bottomRightRadius: false,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    setActive(selected) {
 | 
			
		||||
      return this.setData({ selected });
 | 
			
		||||
    },
 | 
			
		||||
    onClick() {
 | 
			
		||||
      const { parent } = this;
 | 
			
		||||
 | 
			
		||||
      if (!parent || this.properties.disabled) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const index = parent.children.indexOf(this);
 | 
			
		||||
 | 
			
		||||
      parent.setActive(index).then(() => {
 | 
			
		||||
        this.triggerEvent('click', index);
 | 
			
		||||
        parent.triggerEvent('change', { index });
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    setTopRightRadius(val) {
 | 
			
		||||
      return this.setData({
 | 
			
		||||
        topRightRadius: val,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    setBottomRightRadius(val) {
 | 
			
		||||
      return this.setData({
 | 
			
		||||
        bottomRightRadius: val,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,4 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {}
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
<view class="c-sidebar-item-container">
 | 
			
		||||
  <view
 | 
			
		||||
    class="c-sidebar-item {{ selected ? 'active' : '' }} {{ disabled ? 'disabled' : '' }} {{topRightRadius ? 'top-right-radius' : ''}} {{bottomRightRadius ? 'bottom-right-radius' : ''}} custom-class"
 | 
			
		||||
    hover-class="c-sidebar-item--hover"
 | 
			
		||||
    hover-stay-time="70"
 | 
			
		||||
    bind:tap="onClick"
 | 
			
		||||
  >
 | 
			
		||||
    <view class="c-sidebar-item__text text-overflow"> {{ title }} </view>
 | 
			
		||||
  </view>
 | 
			
		||||
</view>
 | 
			
		||||
@@ -0,0 +1,60 @@
 | 
			
		||||
.c-sidebar-item {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
  color: #222427;
 | 
			
		||||
  padding: 20rpx 0;
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.c-sidebar-item.active {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  background: white;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.c-sidebar-item.active::before {
 | 
			
		||||
  content: '';
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  width: 6rpx;
 | 
			
		||||
  height: 48rpx;
 | 
			
		||||
  background-color: #fa4126;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  top: 50%;
 | 
			
		||||
  transform: translate(0, -50%);
 | 
			
		||||
  border-radius: 64rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.c-sidebar-item__text {
 | 
			
		||||
  width: 136rpx;
 | 
			
		||||
  height: 36rpx;
 | 
			
		||||
  padding: 8rpx 0;
 | 
			
		||||
  line-height: 36rpx;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  color: #666666;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.c-sidebar-item.active .c-sidebar-item__text {
 | 
			
		||||
  background-color: white;
 | 
			
		||||
  border-radius: 36rpx;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.text-overflow {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  text-overflow: ellipsis;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.top-right-radius {
 | 
			
		||||
  border-top-right-radius: 16rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bottom-right-radius {
 | 
			
		||||
  border-bottom-right-radius: 16rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.c-sidebar-item-container {
 | 
			
		||||
  background-color: white;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,106 @@
 | 
			
		||||
Component({
 | 
			
		||||
  relations: {
 | 
			
		||||
    './c-sidebar-item/index': {
 | 
			
		||||
      type: 'descendant',
 | 
			
		||||
      linked(target) {
 | 
			
		||||
        this.children.push(target);
 | 
			
		||||
        this.setActive(this.properties.activeKey, true);
 | 
			
		||||
      },
 | 
			
		||||
      unlinked(target) {
 | 
			
		||||
        this.children = this.children.filter((item) => item !== target);
 | 
			
		||||
        this.setActive(this.properties.activeKey, true);
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  externalClasses: ['custom-class'],
 | 
			
		||||
 | 
			
		||||
  properties: {
 | 
			
		||||
    activeKey: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      value: 0,
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  observers: {
 | 
			
		||||
    activeKey(newVal) {
 | 
			
		||||
      this.setActive(newVal);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  created() {
 | 
			
		||||
    this.children = [];
 | 
			
		||||
    this.currentActive = -1;
 | 
			
		||||
    this.topRightRadiusItemIndexs = [];
 | 
			
		||||
    this.bottomRightRadiusItemIndexs = [];
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    setActive(activeKey, isChildrenChange) {
 | 
			
		||||
      const {
 | 
			
		||||
        children,
 | 
			
		||||
        currentActive,
 | 
			
		||||
        topRightRadiusItemIndexs: preTopRightRadiusItemIndexs,
 | 
			
		||||
        bottomRightRadiusItemIndexs: preBottomRightRadiusItemIndexs,
 | 
			
		||||
      } = this;
 | 
			
		||||
 | 
			
		||||
      if (!children.length) {
 | 
			
		||||
        return Promise.resolve();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (activeKey === currentActive && !isChildrenChange) {
 | 
			
		||||
        return Promise.resolve();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.currentActive = activeKey;
 | 
			
		||||
      this.topRightRadiusItemIndexs = this.getTopRightRadiusItemIndexs(
 | 
			
		||||
        activeKey,
 | 
			
		||||
        children,
 | 
			
		||||
      );
 | 
			
		||||
      this.bottomRightRadiusItemIndexs = this.getBottomRightRadiusItemIndexs(
 | 
			
		||||
        activeKey,
 | 
			
		||||
        children,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      const stack = []; // 任务列表,存放调用子组件的setActive后返回的一堆promise
 | 
			
		||||
 | 
			
		||||
      // 将旧的选中项改为false
 | 
			
		||||
      if (currentActive !== activeKey && children[currentActive]) {
 | 
			
		||||
        stack.push(children[currentActive].setActive(false));
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // 将新的选中项改为true
 | 
			
		||||
      if (children[activeKey]) {
 | 
			
		||||
        stack.push(children[activeKey].setActive(true));
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      preTopRightRadiusItemIndexs.forEach((item) => {
 | 
			
		||||
        stack.push(children[item].setTopRightRadius(false));
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      preBottomRightRadiusItemIndexs.forEach((item) => {
 | 
			
		||||
        stack.push(children[item].setBottomRightRadius(false));
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      this.topRightRadiusItemIndexs.forEach((item) => {
 | 
			
		||||
        stack.push(children[item].setTopRightRadius(true));
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      this.bottomRightRadiusItemIndexs.forEach((item) => {
 | 
			
		||||
        stack.push(children[item].setBottomRightRadius(true));
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      return Promise.all(stack);
 | 
			
		||||
    },
 | 
			
		||||
    getTopRightRadiusItemIndexs(activeKey, children) {
 | 
			
		||||
      const { length } = children;
 | 
			
		||||
      if (activeKey !== 0 && activeKey < length - 1) return [0, activeKey + 1];
 | 
			
		||||
      if (activeKey !== 0) return [0];
 | 
			
		||||
      if (activeKey < length - 1) return [activeKey + 1];
 | 
			
		||||
      return [];
 | 
			
		||||
    },
 | 
			
		||||
    getBottomRightRadiusItemIndexs(activeKey) {
 | 
			
		||||
      if (activeKey !== 0) return [activeKey - 1];
 | 
			
		||||
      return [];
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,4 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true
 | 
			
		||||
}
 | 
			
		||||
  
 | 
			
		||||
@@ -0,0 +1,3 @@
 | 
			
		||||
<scroll-view class="c-sidebar custom-class" scroll-y>
 | 
			
		||||
  <slot />
 | 
			
		||||
</scroll-view>
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
.c-sidebar {
 | 
			
		||||
  width: 176rpx;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
}
 | 
			
		||||
.c-sidebar::-webkit-scrollbar {
 | 
			
		||||
  width: 0;
 | 
			
		||||
  height: 0;
 | 
			
		||||
  color: transparent;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,37 @@
 | 
			
		||||
Component({
 | 
			
		||||
  externalClasses: ['custom-class'],
 | 
			
		||||
 | 
			
		||||
  properties: {
 | 
			
		||||
    tabList: Array,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  data: {
 | 
			
		||||
    unfolded: false,
 | 
			
		||||
    boardMaxHeight: null,
 | 
			
		||||
  },
 | 
			
		||||
  attached() {
 | 
			
		||||
    wx.createSelectorQuery()
 | 
			
		||||
      .in(this)
 | 
			
		||||
      .select('.c-tabbar-more')
 | 
			
		||||
      .boundingClientRect((rect) => {
 | 
			
		||||
        this.setData({ boardMaxHeight: rect.height });
 | 
			
		||||
      })
 | 
			
		||||
      .exec();
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    changeFold() {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        unfolded: !this.data.unfolded,
 | 
			
		||||
      });
 | 
			
		||||
      const { unfolded } = this.data;
 | 
			
		||||
      this.triggerEvent('change', { unfolded });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onSelect(event) {
 | 
			
		||||
      const activeKey = event.currentTarget.dataset.index;
 | 
			
		||||
      this.triggerEvent('select', activeKey);
 | 
			
		||||
      this.changeFold();
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,4 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {}
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,25 @@
 | 
			
		||||
<view class="c-tabbar-more">
 | 
			
		||||
  <view class="c-tabbar-more__btn" bind:tap="changeFold">
 | 
			
		||||
    <view class="wr {{unfolded ? 'wr-arrow-up':'wr-arrow-down'}}"></view>
 | 
			
		||||
  </view>
 | 
			
		||||
  <view class="t-tabbar-more__boardwrapper" wx:if="{{ unfolded }}">
 | 
			
		||||
    <view class="t-tabbar-more__mask"></view>
 | 
			
		||||
    <scroll-view
 | 
			
		||||
      class="c-tabbar-more__board"
 | 
			
		||||
      style="{{ boardMaxHeight ? 'height:' + boardMaxHeight + 'px;' : '' }}"
 | 
			
		||||
      scroll-y
 | 
			
		||||
    >
 | 
			
		||||
      <view class="c-tabbar-more__boardinner">
 | 
			
		||||
        <view
 | 
			
		||||
          class="c-tabbar-more__item text-overflow"
 | 
			
		||||
          wx:for="{{ tabList }}"
 | 
			
		||||
          wx:key="index"
 | 
			
		||||
          data-index="{{ index }}"
 | 
			
		||||
          bind:tap="onSelect"
 | 
			
		||||
        >
 | 
			
		||||
          {{ item.name }}
 | 
			
		||||
        </view>
 | 
			
		||||
      </view>
 | 
			
		||||
    </scroll-view>
 | 
			
		||||
  </view>
 | 
			
		||||
</view>
 | 
			
		||||
@@ -0,0 +1,63 @@
 | 
			
		||||
.c-tabbar-more {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: calc(100% - var(--tabbar-height, 100rpx));
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: var(--tabbar-height, 100rpx);
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar-more__btn {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: calc(0rpx - var(--tabbar-height, 100rpx));
 | 
			
		||||
  right: 0;
 | 
			
		||||
  width: 80rpx;
 | 
			
		||||
  height: var(--tabbar-height, 100rpx);
 | 
			
		||||
  line-height: var(--tabbar-height, 100rpx);
 | 
			
		||||
  background-color: var(--tabbar-background-color, white);
 | 
			
		||||
  box-shadow: -20rpx 0 20rpx -10rpx var(--tabbar-background-color, white);
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar-more__btn .market {
 | 
			
		||||
  font-size: 20rpx;
 | 
			
		||||
}
 | 
			
		||||
.t-tabbar-more__boardwrapper {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
}
 | 
			
		||||
.t-tabbar-more__mask {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  background-color: rgba(0, 0, 0, 0.5);
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar-more__board {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  max-height: 100%;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar-more__boardinner {
 | 
			
		||||
  padding: 20rpx 0 20rpx 20rpx;
 | 
			
		||||
  background-color: var(--tabbar-background-color, white);
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-flow: row wrap;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar-more__item {
 | 
			
		||||
  margin: 0 20rpx 20rpx 0;
 | 
			
		||||
  flex: 0 0 calc((100% - 60rpx) / 3);
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  padding: 0 10rpx;
 | 
			
		||||
  border-radius: 30rpx;
 | 
			
		||||
  height: 60rpx;
 | 
			
		||||
  line-height: 60rpx;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  font-size: 22rpx;
 | 
			
		||||
  color: #5d5d5d;
 | 
			
		||||
  background-color: #eee;
 | 
			
		||||
}
 | 
			
		||||
.text-overflow {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  text-overflow: ellipsis;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,68 @@
 | 
			
		||||
Component({
 | 
			
		||||
  externalClasses: ['custom-class'],
 | 
			
		||||
 | 
			
		||||
  properties: {
 | 
			
		||||
    activeKey: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      value: 0,
 | 
			
		||||
    },
 | 
			
		||||
    tabList: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      value: [],
 | 
			
		||||
    },
 | 
			
		||||
    showMore: Boolean, // 是否需要下拉功能
 | 
			
		||||
  },
 | 
			
		||||
  observers: {
 | 
			
		||||
    activeKey(newVal) {
 | 
			
		||||
      if (this.properties.tabList && newVal) {
 | 
			
		||||
        this.setActive(newVal).catch((e) => {
 | 
			
		||||
          console.error(e);
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  data: {
 | 
			
		||||
    currentActive: -1,
 | 
			
		||||
  },
 | 
			
		||||
  attached() {
 | 
			
		||||
    this.setActive(this.properties.activeKey).catch((e) => {
 | 
			
		||||
      console.error(e);
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    setActive(activeKey) {
 | 
			
		||||
      if (
 | 
			
		||||
        !this.properties.tabList[activeKey] ||
 | 
			
		||||
        this.properties.tabList[activeKey].disabled
 | 
			
		||||
      ) {
 | 
			
		||||
        return Promise.reject('数据异常或不可操作');
 | 
			
		||||
      }
 | 
			
		||||
      return new Promise((resolve) => {
 | 
			
		||||
        this.setData(
 | 
			
		||||
          {
 | 
			
		||||
            currentActive: activeKey,
 | 
			
		||||
          },
 | 
			
		||||
          () => resolve(),
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    onClick(event) {
 | 
			
		||||
      let activeKey;
 | 
			
		||||
      if (event.type === 'select') {
 | 
			
		||||
        activeKey = event.detail;
 | 
			
		||||
      } else {
 | 
			
		||||
        activeKey = event.currentTarget.dataset.index;
 | 
			
		||||
      }
 | 
			
		||||
      this.setActive(activeKey)
 | 
			
		||||
        .then(() => {
 | 
			
		||||
          const { currentActive } = this.data;
 | 
			
		||||
          this.triggerEvent('change', { index: currentActive });
 | 
			
		||||
        })
 | 
			
		||||
        .catch((e) => {
 | 
			
		||||
          console.error(e);
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "c-tabbar-more": "./c-tabbar-more/index"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,29 @@
 | 
			
		||||
<view class="c-tabbar custom-class">
 | 
			
		||||
  <scroll-view
 | 
			
		||||
    wx:if="{{ tabList.length > 0 }}"
 | 
			
		||||
    class="c-tabbar__scroll"
 | 
			
		||||
    scroll-x="true"
 | 
			
		||||
    scroll-into-view="{{ 'id-' + currentActive }}"
 | 
			
		||||
  >
 | 
			
		||||
    <view
 | 
			
		||||
      class="c-tabbar__inner {{showMore && tabList.length > 4 ? 'c-tabbar__inner_more' : ''}}"
 | 
			
		||||
    >
 | 
			
		||||
      <view
 | 
			
		||||
        wx:for="{{ tabList }}"
 | 
			
		||||
        wx:key="index"
 | 
			
		||||
        id="{{ 'id-' + index }}"
 | 
			
		||||
        class="c-tabbar-item {{ currentActive === index ? 'active' : '' }} {{ item.disabled ? 'disabled' : '' }}"
 | 
			
		||||
        bind:tap="onClick"
 | 
			
		||||
        data-index="{{index}}"
 | 
			
		||||
      >
 | 
			
		||||
        <view class="c-tabbar-item__text"> {{ item.name }} </view>
 | 
			
		||||
      </view>
 | 
			
		||||
    </view>
 | 
			
		||||
  </scroll-view>
 | 
			
		||||
  <c-tabbar-more
 | 
			
		||||
    wx:if="{{ showMore && tabList.length > 4 }}"
 | 
			
		||||
    tabList="{{tabList}}"
 | 
			
		||||
    bindselect="onClick"
 | 
			
		||||
  />
 | 
			
		||||
  <slot />
 | 
			
		||||
</view>
 | 
			
		||||
@@ -0,0 +1,53 @@
 | 
			
		||||
.c-tabbar {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  --tabbar-height: 100rpx;
 | 
			
		||||
  --tabbar-fontsize: 28rpx;
 | 
			
		||||
  --tabbar-background-color: white;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar__inner {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-flow: row nowrap;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar__scroll {
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar__scroll::after {
 | 
			
		||||
  content: '';
 | 
			
		||||
  display: block;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  bottom: -1px;
 | 
			
		||||
  height: 1px;
 | 
			
		||||
  background-color: #eee;
 | 
			
		||||
  z-index: 1;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar__inner.c-tabbar__inner_more::after {
 | 
			
		||||
  content: '';
 | 
			
		||||
  display: block;
 | 
			
		||||
  width: 100rpx;
 | 
			
		||||
  height: 100rpx;
 | 
			
		||||
  flex: none;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar-item {
 | 
			
		||||
  flex: none;
 | 
			
		||||
  height: 100rpx;
 | 
			
		||||
  color: #282828;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  padding: 0 20rpx;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar-item.active:not(.disabled) {
 | 
			
		||||
  color: #0071ce;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar-item.disabled {
 | 
			
		||||
  color: #ccc;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar-item__text {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  height: 100rpx;
 | 
			
		||||
  line-height: 100rpx;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,75 @@
 | 
			
		||||
Component({
 | 
			
		||||
  externalClasses: ['custom-class'],
 | 
			
		||||
 | 
			
		||||
  properties: {
 | 
			
		||||
    category: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
    },
 | 
			
		||||
    initActive: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      value: [],
 | 
			
		||||
      observer(newVal, oldVal) {
 | 
			
		||||
        if (newVal[0] !== oldVal[0]) {
 | 
			
		||||
          this.setActiveKey(newVal[0], 0);
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    isSlotRight: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      value: false,
 | 
			
		||||
    },
 | 
			
		||||
    level: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      value: 3,
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  data: {
 | 
			
		||||
    activeKey: 0,
 | 
			
		||||
    subActiveKey: 0,
 | 
			
		||||
  },
 | 
			
		||||
  attached() {
 | 
			
		||||
    if (this.properties.initActive && this.properties.initActive.length > 0) {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        activeKey: this.properties.initActive[0],
 | 
			
		||||
        subActiveKey: this.properties.initActive[1] || 0,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    onParentChange(event) {
 | 
			
		||||
      this.setActiveKey(event.detail.index, 0).then(() => {
 | 
			
		||||
        this.triggerEvent('change', [
 | 
			
		||||
          this.data.activeKey,
 | 
			
		||||
          this.data.subActiveKey,
 | 
			
		||||
        ]);
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    onChildChange(event) {
 | 
			
		||||
      this.setActiveKey(this.data.activeKey, event.detail.index).then(() => {
 | 
			
		||||
        this.triggerEvent('change', [
 | 
			
		||||
          this.data.activeKey,
 | 
			
		||||
          this.data.subActiveKey,
 | 
			
		||||
        ]);
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    changCategory(event) {
 | 
			
		||||
      const { item } = event.currentTarget.dataset;
 | 
			
		||||
      this.triggerEvent('changeCategory', {
 | 
			
		||||
        item,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    setActiveKey(key, subKey) {
 | 
			
		||||
      return new Promise((resolve) => {
 | 
			
		||||
        this.setData(
 | 
			
		||||
          {
 | 
			
		||||
            activeKey: key,
 | 
			
		||||
            subActiveKey: subKey,
 | 
			
		||||
          },
 | 
			
		||||
          () => {
 | 
			
		||||
            resolve();
 | 
			
		||||
          },
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "c-tabbar": "./components/c-tabbar/index",
 | 
			
		||||
    "c-sidebar": "./components/c-sidebar/index",
 | 
			
		||||
    "c-sidebar-item": "./components/c-sidebar/c-sidebar-item/index",
 | 
			
		||||
    "t-image": "/components/webp-image/index"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,61 @@
 | 
			
		||||
<view class="goods-category custom-class">
 | 
			
		||||
	<c-sidebar custom-class="custom-sidebar" bindchange="onParentChange" activeKey="{{activeKey}}">
 | 
			
		||||
		<c-sidebar-item
 | 
			
		||||
		  wx:for="{{ category }}"
 | 
			
		||||
		  wx:key="index"
 | 
			
		||||
		  title="{{ item.name }}"
 | 
			
		||||
		  disabled="{{ item.disabled }}"
 | 
			
		||||
		/>
 | 
			
		||||
	</c-sidebar>
 | 
			
		||||
	<view class="goods-category__right">
 | 
			
		||||
		<c-tabbar
 | 
			
		||||
		  wx:if="{{isSlotRight}}"
 | 
			
		||||
		  activeKey="{{subActiveKey}}"
 | 
			
		||||
		  bindchange="onChildChange"
 | 
			
		||||
		  showMore
 | 
			
		||||
		>
 | 
			
		||||
			<slot/>
 | 
			
		||||
		</c-tabbar>
 | 
			
		||||
		<view wx:if="{{!isSlotRight}}" class="goods-category-normal">
 | 
			
		||||
			<view class="goods-category-normal-item" wx:if="{{category[activeKey].children && category[activeKey].children.length > 0}}">
 | 
			
		||||
				<block wx:for="{{category[activeKey].children}}" wx:key="index" wx:if="{{level === 3 && item.children && item.children.length > 0}}">
 | 
			
		||||
					<view class="flex goods-category-normal-item-title">
 | 
			
		||||
						{{item.name}}
 | 
			
		||||
					</view>
 | 
			
		||||
					<view class="goods-category-normal-item-container">
 | 
			
		||||
						<view
 | 
			
		||||
						  class="goods-category-normal-item-container-item"
 | 
			
		||||
						  wx:for="{{item.children}}"
 | 
			
		||||
						  wx:for-index="subIndex"
 | 
			
		||||
						  wx:key="subIndex"
 | 
			
		||||
						  wx:for-item="subItem"
 | 
			
		||||
						  bindtap="changCategory"
 | 
			
		||||
						  data-item="{{subItem}}"
 | 
			
		||||
						>
 | 
			
		||||
							<t-image src="{{subItem.thumbnail}}" t-class="image" />
 | 
			
		||||
							<view class="flex goods-category-normal-item-container-item-title">
 | 
			
		||||
								{{subItem.name}}
 | 
			
		||||
							</view>
 | 
			
		||||
						</view>
 | 
			
		||||
					</view>
 | 
			
		||||
				</block>
 | 
			
		||||
				<view class="goods-category-normal-item-second-container" wx:if="{{level === 2}}">
 | 
			
		||||
					<block wx:for="{{category[activeKey].children}}" wx:key="index">
 | 
			
		||||
						<view
 | 
			
		||||
						  class="goods-category-normal-item-second-container-item"
 | 
			
		||||
						  wx:for-key="index"
 | 
			
		||||
						  bindtap="changCategory"
 | 
			
		||||
						  data-item="{{item}}"
 | 
			
		||||
						>
 | 
			
		||||
							<t-image src="{{item.thumbnail}}" t-class="image" />
 | 
			
		||||
							<view class="flex goods-category-normal-item-container-item-title">
 | 
			
		||||
								{{item.name}}
 | 
			
		||||
							</view>
 | 
			
		||||
						</view>
 | 
			
		||||
					</block>
 | 
			
		||||
				</view>
 | 
			
		||||
			</view>
 | 
			
		||||
		</view>
 | 
			
		||||
	</view>
 | 
			
		||||
</view>
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,102 @@
 | 
			
		||||
.goods-category {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.custom-sidebar {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category__right {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  flex: auto;
 | 
			
		||||
  width: 0;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  overflow: scroll;
 | 
			
		||||
  -webkit-overflow-scrolling: touch;
 | 
			
		||||
  background-color: white;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category-normal {
 | 
			
		||||
  margin: 28rpx 34rpx 0rpx 32rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category-normal-item-title {
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  font-weight: 500;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category-normal-item-container {
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
  padding-top: 28rpx;
 | 
			
		||||
  margin-top: -24rpx;
 | 
			
		||||
  margin-bottom: 30rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-wrap: wrap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category-normal-item-container-item {
 | 
			
		||||
  height: 196rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  margin-top: 24rpx;
 | 
			
		||||
  width: 33.3%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category-normal-item-container-item .image {
 | 
			
		||||
  width: 144rpx;
 | 
			
		||||
  height: 144rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category-normal-item-container-item-title {
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  color: #666666;
 | 
			
		||||
  margin-top: 20rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category .custom-sidebar {
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.custom-sidebar {
 | 
			
		||||
  width: 180rpx;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.custom-sidebar::-webkit-scrollbar {
 | 
			
		||||
  width: 0;
 | 
			
		||||
  height: 0;
 | 
			
		||||
  color: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category-normal-item-second-container {
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
  margin-top: 8rpx;
 | 
			
		||||
  margin-bottom: 30rpx;
 | 
			
		||||
  display: grid;
 | 
			
		||||
  grid-template-columns: 33.33% 33.33% 33.33%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category-normal-item-second-container-item {
 | 
			
		||||
  height: 200rpx;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  margin-top: 20rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category-normal-item-second-container-item .image {
 | 
			
		||||
  width: 144rpx;
 | 
			
		||||
  height: 144rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category-normal-item-second-container-item-title {
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  color: #222427;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								mini-program/pages/goods/category/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								mini-program/pages/goods/category/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
import { getCategoryList } from '../../../services/good/fetchCategoryList';
 | 
			
		||||
Page({
 | 
			
		||||
  data: {
 | 
			
		||||
    list: [],
 | 
			
		||||
  },
 | 
			
		||||
  async init() {
 | 
			
		||||
    try {
 | 
			
		||||
      const result = await getCategoryList();
 | 
			
		||||
      this.setData({
 | 
			
		||||
        list: result,
 | 
			
		||||
      });
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      console.error('err:', error);
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onShow() {
 | 
			
		||||
    this.getTabBar().init();
 | 
			
		||||
  },
 | 
			
		||||
  onChange() {
 | 
			
		||||
    wx.navigateTo({
 | 
			
		||||
      url: '/pages/goods/list/index',
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
  onLoad() {
 | 
			
		||||
    this.init(true);
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										6
									
								
								mini-program/pages/goods/category/index.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								mini-program/pages/goods/category/index.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "navigationBarTitleText": "分类",
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "goods-category": "./components/goods-category/index"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								mini-program/pages/goods/category/index.wxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								mini-program/pages/goods/category/index.wxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
<view class="wrap">
 | 
			
		||||
  <goods-category
 | 
			
		||||
    level="{{3}}"
 | 
			
		||||
    custom-class="goods-category-class"
 | 
			
		||||
    category="{{list}}"
 | 
			
		||||
    bind:changeCategory="onChange"
 | 
			
		||||
  />
 | 
			
		||||
</view>
 | 
			
		||||
							
								
								
									
										23
									
								
								mini-program/pages/goods/category/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								mini-program/pages/goods/category/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
.tabbar-position {
 | 
			
		||||
  position: fixed !important;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.wrap {
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
.goods-category-class {
 | 
			
		||||
  background-color: #f6f6f6 !important;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
}
 | 
			
		||||
.goods-category-class .goods-category-normal-item-container-item {
 | 
			
		||||
  margin-top: 20rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
page {
 | 
			
		||||
  min-height: none;
 | 
			
		||||
  padding-bottom: 0;
 | 
			
		||||
}
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 1.3 KiB  | 
@@ -0,0 +1,36 @@
 | 
			
		||||
// pages/goods/comments/components/comments-card/images-videos/index.js
 | 
			
		||||
Component({
 | 
			
		||||
  /**
 | 
			
		||||
   * 组件的属性列表
 | 
			
		||||
   */
 | 
			
		||||
  properties: {
 | 
			
		||||
    resources: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      value: [],
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 组件的初始数据
 | 
			
		||||
   */
 | 
			
		||||
  data: {
 | 
			
		||||
    classType: 'single',
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  observers: {
 | 
			
		||||
    resources: function (newVal) {
 | 
			
		||||
      if (newVal.length <= 1) {
 | 
			
		||||
        this.setData({ classType: 'single' });
 | 
			
		||||
      } else if (newVal.length === 2) {
 | 
			
		||||
        this.setData({ classType: 'double' });
 | 
			
		||||
      } else {
 | 
			
		||||
        this.setData({ classType: 'multiple' });
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 组件的方法列表
 | 
			
		||||
   */
 | 
			
		||||
  methods: {},
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "my-video": "../my-video/index",
 | 
			
		||||
    "t-image": "/components/webp-image/index"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,15 @@
 | 
			
		||||
<view class="images-videos-container container-{{classType}}">
 | 
			
		||||
	<view
 | 
			
		||||
	  class="resource-container resource-container-{{classType}}"
 | 
			
		||||
	  wx:for="{{resources}}"
 | 
			
		||||
	  wx:for-item="resource"
 | 
			
		||||
	  wx:key="*this"
 | 
			
		||||
	>
 | 
			
		||||
		<t-image wx:if="{{resource.type === 'image'}}" t-class="resource-item-{{classType}}" src="{{resource.src}}" />
 | 
			
		||||
		<my-video wx:else videoSrc="{{resource.src}} " my-video="resource-item-{{classType}}">
 | 
			
		||||
			<t-image t-class="resource-item resource-item-{{classType}}" slot="cover-img" src="{{resource.coverSrc}}" />
 | 
			
		||||
			<image class="play-icon" slot="play-icon" src="./assets/play.png" />
 | 
			
		||||
		</my-video>
 | 
			
		||||
	</view>
 | 
			
		||||
</view>
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,68 @@
 | 
			
		||||
.resource-item-single {
 | 
			
		||||
  width: 360rpx;
 | 
			
		||||
  height: 360rpx;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.resource-item-double {
 | 
			
		||||
  width: 334rpx;
 | 
			
		||||
  height: 334rpx;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.resource-item-multiple {
 | 
			
		||||
  width: 218rpx;
 | 
			
		||||
  height: 218rpx;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.resource-container-single {
 | 
			
		||||
  padding-left: 0;
 | 
			
		||||
  padding-top: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.resource-container-double {
 | 
			
		||||
  padding-left: 18rpx;
 | 
			
		||||
  padding-top: 18rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.resource-container-multiple {
 | 
			
		||||
  padding-left: 16rpx;
 | 
			
		||||
  padding-top: 16rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.container-single {
 | 
			
		||||
  margin-left: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.container-double {
 | 
			
		||||
  margin-left: -18rpx;
 | 
			
		||||
  margin-top: -18rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.container-multiple {
 | 
			
		||||
  margin-left: -16rpx;
 | 
			
		||||
  margin-top: -16rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.resource-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.play-icon {
 | 
			
		||||
  width: 96rpx;
 | 
			
		||||
  height: 96rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.images-videos-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-wrap: wrap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.image {
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.cover-img-container {
 | 
			
		||||
  background-color: white;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
Component({
 | 
			
		||||
  externalClasses: ['my-video', 'my-cover-img', 'my-play-icon'],
 | 
			
		||||
  properties: {
 | 
			
		||||
    videoSrc: { type: String },
 | 
			
		||||
  },
 | 
			
		||||
  data: {
 | 
			
		||||
    isShow: true,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  options: {
 | 
			
		||||
    multipleSlots: true, // 在组件定义时的选项中启用多slot支持
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  attached() {
 | 
			
		||||
    this.videoContext = wx.createVideoContext('myVideo', this);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  fullScreen: false,
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    // 点击封面自定义播放按钮时触发
 | 
			
		||||
    bindplay(e) {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        isShow: false,
 | 
			
		||||
      });
 | 
			
		||||
      this.videoContext.play();
 | 
			
		||||
      this.triggerEvent('play', e);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    bindplayByVideo(e) {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        isShow: false,
 | 
			
		||||
      });
 | 
			
		||||
      this.triggerEvent('play', e);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 监听播放到末尾时触发
 | 
			
		||||
    bindended(e) {
 | 
			
		||||
      if (!this.fullScreen) {
 | 
			
		||||
        this.setData({
 | 
			
		||||
          isShow: true,
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
      this.triggerEvent('ended', e);
 | 
			
		||||
    },
 | 
			
		||||
    // 监听暂停播放时触发
 | 
			
		||||
    bindpause(e) {
 | 
			
		||||
      this.triggerEvent('pause', e);
 | 
			
		||||
    },
 | 
			
		||||
    bindfullscreenchange(e) {
 | 
			
		||||
      const fullScreen = e?.detail?.fullScreen;
 | 
			
		||||
      this.fullScreen = fullScreen;
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,4 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {}
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,26 @@
 | 
			
		||||
<video
 | 
			
		||||
  id="myVideo"
 | 
			
		||||
  src="{{videoSrc}}"
 | 
			
		||||
  enable-danmu
 | 
			
		||||
  controls
 | 
			
		||||
  show-fullscreen-btn
 | 
			
		||||
  show-center-play-btn="{{false}}"
 | 
			
		||||
  auto-pause-if-navigate
 | 
			
		||||
  auto-pause-if-open-native
 | 
			
		||||
  show-play-btn
 | 
			
		||||
  object-fit="contain"
 | 
			
		||||
  bindpause="bindpause"
 | 
			
		||||
  bindended="bindended"
 | 
			
		||||
  bindplay="bindplayByVideo"
 | 
			
		||||
  class="video my-video"
 | 
			
		||||
  bindfullscreenchange="bindfullscreenchange"
 | 
			
		||||
>
 | 
			
		||||
  <view class="video_cover" wx:if="{{isShow}}">
 | 
			
		||||
    <view class="my-cover-img">
 | 
			
		||||
      <slot name="cover-img" />
 | 
			
		||||
    </view>
 | 
			
		||||
    <view class="video_play_icon my-play-icon" bindtap="bindplay">
 | 
			
		||||
      <slot name="play-icon" />
 | 
			
		||||
    </view>
 | 
			
		||||
  </view>
 | 
			
		||||
</video>
 | 
			
		||||
@@ -0,0 +1,21 @@
 | 
			
		||||
.video .video_cover {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.video .video_play_icon {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  left: 50%;
 | 
			
		||||
  top: 50%;
 | 
			
		||||
  transform: translate(-50%, -50%);
 | 
			
		||||
  z-index: 5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.video .video_txt {
 | 
			
		||||
  margin: 10rpx auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.video {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,51 @@
 | 
			
		||||
Component({
 | 
			
		||||
  externalClasses: ['wr-class'],
 | 
			
		||||
  options: {
 | 
			
		||||
    multipleSlots: true,
 | 
			
		||||
  },
 | 
			
		||||
  properties: {
 | 
			
		||||
    goodsDetailInfo: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
    sellerReply: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
    userHeadUrl: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
    userName: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: '',
 | 
			
		||||
    },
 | 
			
		||||
    commentContent: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
    commentScore: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      value: 0,
 | 
			
		||||
    },
 | 
			
		||||
    commentTime: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
    commentResources: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      value: [],
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  data: {
 | 
			
		||||
    showMoreStatus: false,
 | 
			
		||||
    showContent: false,
 | 
			
		||||
    hideText: false,
 | 
			
		||||
    eleHeight: null,
 | 
			
		||||
    overText: false,
 | 
			
		||||
    isDisabled: true,
 | 
			
		||||
    startColors: ['#FFC51C', '#DDDDDD'],
 | 
			
		||||
  },
 | 
			
		||||
  methods: {},
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "t-rate": "tdesign-miniprogram/rate/rate",
 | 
			
		||||
    "images-videos": "./components/images-videos",
 | 
			
		||||
    "t-image": "/components/webp-image/index"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,27 @@
 | 
			
		||||
<view class="comments-card-item wr-class">
 | 
			
		||||
  <view class="comments-card-item-container">
 | 
			
		||||
    <view class="comments-title">
 | 
			
		||||
      <view class="comments-card-item-userImg">
 | 
			
		||||
        <t-image t-class="userImg" src="{{userHeadUrl}}" />
 | 
			
		||||
      </view>
 | 
			
		||||
      <view class="userName">{{userName}}</view>
 | 
			
		||||
      <text class="commentTime">{{commentTime}}</text>
 | 
			
		||||
    </view>
 | 
			
		||||
    <view class="comments-info">
 | 
			
		||||
      <view class="rate">
 | 
			
		||||
        <t-rate value="{{commentScore}}" size="14" gap="2" color="{{['#ffc51c', '#ddd']}}" />
 | 
			
		||||
      </view>
 | 
			
		||||
      <view class="goods-info-text" wx:if="{{goodsDetailInfo}}">{{goodsDetailInfo}}</view>
 | 
			
		||||
    </view>
 | 
			
		||||
    <view class="comments-card-item-container-content">
 | 
			
		||||
      <view class="content-text" hidden="{{showContent}}"> {{commentContent}} </view>
 | 
			
		||||
    </view>
 | 
			
		||||
    <view class="comments-card-item-container-image" wx:if="{{commentResources.length > 0}}">
 | 
			
		||||
      <images-videos resources="{{commentResources}}" />
 | 
			
		||||
    </view>
 | 
			
		||||
    <view class="comments-card-reply" wx:if="{{sellerReply}}">
 | 
			
		||||
      <text class="prefix">店家回复:</text>
 | 
			
		||||
      <text class="content">{{sellerReply}}</text>
 | 
			
		||||
    </view>
 | 
			
		||||
  </view>
 | 
			
		||||
</view>
 | 
			
		||||
@@ -0,0 +1,172 @@
 | 
			
		||||
@import '../../../../../style/theme.wxss';
 | 
			
		||||
 | 
			
		||||
.comments-card-item {
 | 
			
		||||
  padding: 32rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item::after {
 | 
			
		||||
  content: '';
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  bottom: 0rpx;
 | 
			
		||||
  width: 686rpx;
 | 
			
		||||
  height: 2rpx;
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-userImg {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-userImg .userImg {
 | 
			
		||||
  width: 64rpx;
 | 
			
		||||
  height: 64rpx;
 | 
			
		||||
  border-radius: 50%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-name {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  color: #333;
 | 
			
		||||
  font-weight: 600;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-name .userName {
 | 
			
		||||
  margin-right: 12rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-date {
 | 
			
		||||
  font-size: 22rpx;
 | 
			
		||||
  color: #999;
 | 
			
		||||
  margin-top: 4rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-content {
 | 
			
		||||
  margin-top: 16rpx;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-content .content-text {
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  white-space: normal;
 | 
			
		||||
  word-break: break-all;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-content .hide-text {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  text-overflow: ellipsis;
 | 
			
		||||
  -webkit-line-clamp: 5;
 | 
			
		||||
  text-align: justify;
 | 
			
		||||
  display: -webkit-box;
 | 
			
		||||
  -webkit-box-orient: vertical;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-content .showMore {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  width: 112rpx;
 | 
			
		||||
  height: 36rpx;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  background: linear-gradient(
 | 
			
		||||
    to right,
 | 
			
		||||
    rgba(255, 255, 255, 0.2) 0,
 | 
			
		||||
    rgba(255, 255, 255, 0.45) 20%,
 | 
			
		||||
    rgba(255, 255, 255, 0.7) 25%,
 | 
			
		||||
    rgba(255, 255, 255, 0.9) 30%,
 | 
			
		||||
    rgba(255, 255, 255, 0.95) 35%,
 | 
			
		||||
    #ffffff 50%,
 | 
			
		||||
    #fff 100%
 | 
			
		||||
  );
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  color: #fa550f;
 | 
			
		||||
  line-height: 36rpx;
 | 
			
		||||
  text-align: right;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-image {
 | 
			
		||||
  margin-top: 24rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  flex-wrap: wrap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-image .commentImg {
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
  margin-top: 12rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-image .commentImg3 {
 | 
			
		||||
  width: 196rpx;
 | 
			
		||||
  height: 196rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-image .commentImg2 {
 | 
			
		||||
  width: 300rpx;
 | 
			
		||||
  height: 300rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-image .commentImg1 {
 | 
			
		||||
  width: 404rpx;
 | 
			
		||||
  height: 404rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container .comments-title {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-title .userName {
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  color: #333333;
 | 
			
		||||
  margin-left: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-title .commentTime {
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  color: #999999;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  right: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-info {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  margin-top: 18rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-info .rate {
 | 
			
		||||
  margin-right: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-info .goods-info-text {
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
 | 
			
		||||
  color: #999999;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container .comments-card-reply {
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
  padding: 24rpx 16rpx;
 | 
			
		||||
  margin-top: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container .comments-card-reply .prefix {
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  color: #666666;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container .comments-card-reply .content {
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  color: #666666;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										86
									
								
								mini-program/pages/goods/comments/create/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								mini-program/pages/goods/comments/create/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
			
		||||
// import { getCommentDetail } from '../../../../services/good/comments/fetchCommentDetail';
 | 
			
		||||
import Toast from 'tdesign-miniprogram/toast/index';
 | 
			
		||||
Page({
 | 
			
		||||
  data: {
 | 
			
		||||
    serviceRateValue: 1,
 | 
			
		||||
    goodRateValue: 1,
 | 
			
		||||
    conveyRateValue: 1,
 | 
			
		||||
    isAnonymous: false,
 | 
			
		||||
    uploadFiles: [],
 | 
			
		||||
    gridConfig: {
 | 
			
		||||
      width: 218,
 | 
			
		||||
      height: 218,
 | 
			
		||||
      column: 3,
 | 
			
		||||
    },
 | 
			
		||||
    isAllowedSubmit: false,
 | 
			
		||||
    imgUrl: '',
 | 
			
		||||
    title: '',
 | 
			
		||||
    goodsDetail: '',
 | 
			
		||||
    imageProps: {
 | 
			
		||||
      mode: 'aspectFit',
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onLoad(options) {
 | 
			
		||||
    this.setData({
 | 
			
		||||
      imgUrl: options.imgUrl,
 | 
			
		||||
      title: options.title,
 | 
			
		||||
      goodsDetail: options.specs,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onRateChange(e) {
 | 
			
		||||
    const { value } = e?.detail;
 | 
			
		||||
    const item = e?.currentTarget?.dataset?.item;
 | 
			
		||||
    this.setData({ [item]: value }, () => {
 | 
			
		||||
      this.updateButtonStatus();
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onAnonymousChange(e) {
 | 
			
		||||
    const status = !!e?.detail?.checked;
 | 
			
		||||
    this.setData({ isAnonymous: status });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  handleSuccess(e) {
 | 
			
		||||
    const { files } = e.detail;
 | 
			
		||||
 | 
			
		||||
    this.setData({
 | 
			
		||||
      uploadFiles: files,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  handleRemove(e) {
 | 
			
		||||
    const { index } = e.detail;
 | 
			
		||||
    const { uploadFiles } = this.data;
 | 
			
		||||
    uploadFiles.splice(index, 1);
 | 
			
		||||
    this.setData({
 | 
			
		||||
      uploadFiles,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onTextAreaChange(e) {
 | 
			
		||||
    const value = e?.detail?.value;
 | 
			
		||||
    this.textAreaValue = value;
 | 
			
		||||
    this.updateButtonStatus();
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  updateButtonStatus() {
 | 
			
		||||
    const { serviceRateValue, goodRateValue, conveyRateValue, isAllowedSubmit } = this.data;
 | 
			
		||||
    const { textAreaValue } = this;
 | 
			
		||||
    const temp = serviceRateValue && goodRateValue && conveyRateValue && textAreaValue;
 | 
			
		||||
    if (temp !== isAllowedSubmit) this.setData({ isAllowedSubmit: temp });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onSubmitBtnClick() {
 | 
			
		||||
    const { isAllowedSubmit } = this.data;
 | 
			
		||||
    if (!isAllowedSubmit) return;
 | 
			
		||||
    Toast({
 | 
			
		||||
      context: this,
 | 
			
		||||
      selector: '#t-toast',
 | 
			
		||||
      message: '评价提交成功',
 | 
			
		||||
      icon: 'check-circle',
 | 
			
		||||
    });
 | 
			
		||||
    wx.navigateBack();
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										13
									
								
								mini-program/pages/goods/comments/create/index.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								mini-program/pages/goods/comments/create/index.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
{
 | 
			
		||||
  "navigationBarTitleText": "评价商品",
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "t-image": "/components/webp-image/index",
 | 
			
		||||
    "t-rate": "tdesign-miniprogram/rate/rate",
 | 
			
		||||
    "t-textarea": "tdesign-miniprogram/textarea/textarea",
 | 
			
		||||
    "t-checkbox": "tdesign-miniprogram/checkbox/checkbox",
 | 
			
		||||
    "t-button": "tdesign-miniprogram/button/button",
 | 
			
		||||
    "t-upload": "tdesign-miniprogram/upload/upload",
 | 
			
		||||
    "t-icon": "tdesign-miniprogram/icon/icon",
 | 
			
		||||
    "t-toast": "tdesign-miniprogram/toast/toast"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										90
									
								
								mini-program/pages/goods/comments/create/index.wxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								mini-program/pages/goods/comments/create/index.wxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
			
		||||
<view class="page-container">
 | 
			
		||||
  <view class="comment-card">
 | 
			
		||||
    <view class="goods-info-container">
 | 
			
		||||
      <view class="goods-image-container">
 | 
			
		||||
        <t-image t-class="goods-image" src="{{imgUrl}}" />
 | 
			
		||||
      </view>
 | 
			
		||||
      <view class="goods-title-container">
 | 
			
		||||
        <view class="goods-title">{{title}}</view>
 | 
			
		||||
        <view class="goods-detail">{{goodsDetail}}</view>
 | 
			
		||||
      </view>
 | 
			
		||||
    </view>
 | 
			
		||||
    <view class="rate-container">
 | 
			
		||||
      <text class="rate-title">商品评价</text>
 | 
			
		||||
      <view class="rate">
 | 
			
		||||
        <t-rate
 | 
			
		||||
          value="{{goodRateValue}}"
 | 
			
		||||
          bind:change="onRateChange"
 | 
			
		||||
          size="26"
 | 
			
		||||
          gap="6"
 | 
			
		||||
          color="{{['#ffc51c', '#ddd']}}"
 | 
			
		||||
          data-item="goodRateValue"
 | 
			
		||||
        />
 | 
			
		||||
      </view>
 | 
			
		||||
    </view>
 | 
			
		||||
    <view class="textarea-container">
 | 
			
		||||
      <t-textarea
 | 
			
		||||
        t-class="textarea"
 | 
			
		||||
        maxlength="{{500}}"
 | 
			
		||||
        indicator
 | 
			
		||||
        placeholder="对商品满意吗?评论一下"
 | 
			
		||||
        bind:change="onTextAreaChange"
 | 
			
		||||
      />
 | 
			
		||||
    </view>
 | 
			
		||||
    <view class="upload-container">
 | 
			
		||||
      <t-upload
 | 
			
		||||
        media-type="{{['image','video']}}"
 | 
			
		||||
        files="{{uploadFiles}}"
 | 
			
		||||
        bind:remove="handleRemove"
 | 
			
		||||
        bind:success="handleSuccess"
 | 
			
		||||
        gridConfig="{{gridConfig}}"
 | 
			
		||||
        imageProps="{{imageProps}}"
 | 
			
		||||
      />
 | 
			
		||||
    </view>
 | 
			
		||||
 | 
			
		||||
    <view class="anonymous-box">
 | 
			
		||||
      <t-checkbox bind:change="onAnonymousChange" checked="{{isAnonymous}}" color="#FA4126" />
 | 
			
		||||
      <view class="name">匿名评价</view>
 | 
			
		||||
    </view>
 | 
			
		||||
  </view>
 | 
			
		||||
</view>
 | 
			
		||||
<view class="comment-card convey-card">
 | 
			
		||||
  <view class="convey-comment-title">物流服务评价</view>
 | 
			
		||||
  <view class="rate-container">
 | 
			
		||||
    <text class="rate-title">物流评价</text>
 | 
			
		||||
    <view class="rate">
 | 
			
		||||
      <t-rate
 | 
			
		||||
        value="{{conveyRateValue}}"
 | 
			
		||||
        bind:change="onRateChange"
 | 
			
		||||
        variant="filled"
 | 
			
		||||
        size="26"
 | 
			
		||||
        gap="6"
 | 
			
		||||
        color="{{['#ffc51c', '#ddd']}}"
 | 
			
		||||
        data-item="conveyRateValue"
 | 
			
		||||
      />
 | 
			
		||||
    </view>
 | 
			
		||||
  </view>
 | 
			
		||||
  <view class="rate-container">
 | 
			
		||||
    <text class="rate-title">服务评价</text>
 | 
			
		||||
    <view class="rate">
 | 
			
		||||
      <t-rate
 | 
			
		||||
        value="{{serviceRateValue}}"
 | 
			
		||||
        bind:change="onRateChange"
 | 
			
		||||
        size="26"
 | 
			
		||||
        gap="6"
 | 
			
		||||
        color="{{['#ffc51c', '#ddd']}}"
 | 
			
		||||
        data-item="serviceRateValue"
 | 
			
		||||
      />
 | 
			
		||||
    </view>
 | 
			
		||||
  </view>
 | 
			
		||||
</view>
 | 
			
		||||
<view class="submit-button-container">
 | 
			
		||||
  <t-button
 | 
			
		||||
    content="提交"
 | 
			
		||||
    block
 | 
			
		||||
    shape="round"
 | 
			
		||||
    t-class="submit-button{{isAllowedSubmit ? '' : '-disabled'}}"
 | 
			
		||||
    bind:tap="onSubmitBtnClick"
 | 
			
		||||
  />
 | 
			
		||||
</view>
 | 
			
		||||
<t-toast id="t-toast" />
 | 
			
		||||
							
								
								
									
										168
									
								
								mini-program/pages/goods/comments/create/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								mini-program/pages/goods/comments/create/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,168 @@
 | 
			
		||||
page {
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .comment-card {
 | 
			
		||||
  padding: 24rpx 32rpx 28rpx;
 | 
			
		||||
  background-color: #ffffff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-card .goods-info-container .goods-image {
 | 
			
		||||
  width: 112rpx;
 | 
			
		||||
  height: 112rpx;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-card .goods-info-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-card .goods-info-container .goods-title-container {
 | 
			
		||||
  padding-left: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-card .goods-info-container .goods-title {
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-card .goods-info-container .goods-detail {
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
  color: #999999;
 | 
			
		||||
  margin-top: 16rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-card .rate-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  margin-top: 22rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-card .rate-container .rate-title {
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  margin-right: 12rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-card .textarea-container {
 | 
			
		||||
  margin-top: 22rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-card .textarea-container .textarea {
 | 
			
		||||
  height: 294rpx;
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
  border-radius: 16rpx;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .t-checkbox__bordered {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .anonymous-box {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  padding-top: 52rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .anonymous-box .name {
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
  color: #999999;
 | 
			
		||||
  padding-left: 28rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .t-checkbox {
 | 
			
		||||
  padding: 0rpx !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .t-checkbox__content {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-card .convey-comment-title {
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.convey-card {
 | 
			
		||||
  background-color: #ffffff;
 | 
			
		||||
  margin-top: 24rpx;
 | 
			
		||||
  padding: 32rpx;
 | 
			
		||||
  padding-bottom: calc(env(safe-area-inset-bottom) + 140rpx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.convey-card .rate-container .rate-title {
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .t-checkbox__icon-left {
 | 
			
		||||
  margin-right: 0rpx !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.submit-button-container {
 | 
			
		||||
  padding: 12rpx 32rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  width: 100vw;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  padding-bottom: calc(env(safe-area-inset-bottom) + 20rpx);
 | 
			
		||||
  background-color: #ffffff;
 | 
			
		||||
  z-index: 99;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.submit-button-container .submit-button {
 | 
			
		||||
  --td-button-default-color: #fff;
 | 
			
		||||
  --td-button-default-bg-color: #fa4126;
 | 
			
		||||
  --td-button-default-border-color: #fa4126;
 | 
			
		||||
  --td-button-default-active-bg-color: #fa42269c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.submit-button-container .submit-button-disabled {
 | 
			
		||||
  --td-button-default-color: #fff;
 | 
			
		||||
  --td-button-default-bg-color: #ccc;
 | 
			
		||||
  --td-button-default-border-color: #ccc;
 | 
			
		||||
  --td-button-default-active-bg-color: rgba(204, 204, 204, 0.789);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .upload-container {
 | 
			
		||||
  margin-top: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .t-upload__wrapper {
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .submmit-bar {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  z-index: 12;
 | 
			
		||||
  padding: 12rpx 32rpx;
 | 
			
		||||
  padding-bottom: env(safe-area-inset-bottom);
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  height: 112rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .submmit-bar-button {
 | 
			
		||||
  border-radius: 48rpx !important;
 | 
			
		||||
  padding: 0 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .t-upload__close-btn {
 | 
			
		||||
  background-color: rgba(0, 0, 0, 0.4);
 | 
			
		||||
  border-bottom-left-radius: 8rpx;
 | 
			
		||||
  width: 36rpx;
 | 
			
		||||
  height: 36rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.upload-container .upload-addcontent-slot {
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										227
									
								
								mini-program/pages/goods/comments/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								mini-program/pages/goods/comments/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,227 @@
 | 
			
		||||
import { fetchComments } from '../../../services/comments/fetchComments';
 | 
			
		||||
import { fetchCommentsCount } from '../../../services/comments/fetchCommentsCount';
 | 
			
		||||
import dayjs from 'dayjs';
 | 
			
		||||
const layoutMap = {
 | 
			
		||||
  0: 'vertical',
 | 
			
		||||
};
 | 
			
		||||
Page({
 | 
			
		||||
  data: {
 | 
			
		||||
    pageLoading: false,
 | 
			
		||||
    commentList: [],
 | 
			
		||||
    pageNum: 1,
 | 
			
		||||
    myPageNum: 1,
 | 
			
		||||
    pageSize: 10,
 | 
			
		||||
    total: 0,
 | 
			
		||||
    myTotal: 0,
 | 
			
		||||
    hasLoaded: false,
 | 
			
		||||
    layoutText: layoutMap[0],
 | 
			
		||||
    loadMoreStatus: 0,
 | 
			
		||||
    myLoadStatus: 0,
 | 
			
		||||
    spuId: '1060004',
 | 
			
		||||
    commentLevel: '',
 | 
			
		||||
    hasImage: '',
 | 
			
		||||
    commentType: '',
 | 
			
		||||
    totalCount: 0,
 | 
			
		||||
    countObj: {
 | 
			
		||||
      badCount: '0',
 | 
			
		||||
      commentCount: '0',
 | 
			
		||||
      goodCount: '0',
 | 
			
		||||
      middleCount: '0',
 | 
			
		||||
      hasImageCount: '0',
 | 
			
		||||
      uidCount: '0',
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  onLoad(options) {
 | 
			
		||||
    this.getCount(options);
 | 
			
		||||
    this.getComments(options);
 | 
			
		||||
  },
 | 
			
		||||
  async getCount(options) {
 | 
			
		||||
    try {
 | 
			
		||||
      const result = await fetchCommentsCount(
 | 
			
		||||
        {
 | 
			
		||||
          spuId: options.spuId,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          method: 'POST',
 | 
			
		||||
        },
 | 
			
		||||
      );
 | 
			
		||||
      this.setData({
 | 
			
		||||
        countObj: result,
 | 
			
		||||
      });
 | 
			
		||||
      // const { data, code = '' } = result;
 | 
			
		||||
      // if (code.toUpperCase() === 'SUCCESS') {
 | 
			
		||||
      //     wx.setNavigationBarTitle({
 | 
			
		||||
      //     title: `全部评价(${data.commentCount})`,
 | 
			
		||||
      //     });
 | 
			
		||||
      //     this.setData({
 | 
			
		||||
      //     countObj: data,
 | 
			
		||||
      //     });
 | 
			
		||||
      // } else {
 | 
			
		||||
      //     wx.showToast({
 | 
			
		||||
      //     title: '查询失败,请稍候重试',
 | 
			
		||||
      //     });
 | 
			
		||||
      // }
 | 
			
		||||
    } catch (error) {}
 | 
			
		||||
  },
 | 
			
		||||
  generalQueryData(reset) {
 | 
			
		||||
    const { hasImage, pageNum, pageSize, spuId, commentLevel } = this.data;
 | 
			
		||||
    const params = {
 | 
			
		||||
      pageNum: 1,
 | 
			
		||||
      pageSize: 30,
 | 
			
		||||
      queryParameter: {
 | 
			
		||||
        spuId,
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
    if (
 | 
			
		||||
      Number(commentLevel) === 3 ||
 | 
			
		||||
      Number(commentLevel) === 2 ||
 | 
			
		||||
      Number(commentLevel) === 1
 | 
			
		||||
    ) {
 | 
			
		||||
      params.queryParameter.commentLevel = Number(commentLevel);
 | 
			
		||||
    }
 | 
			
		||||
    if (hasImage && hasImage === '1') {
 | 
			
		||||
      params.queryParameter.hasImage = true;
 | 
			
		||||
    } else {
 | 
			
		||||
      delete params.queryParameter.hasImage;
 | 
			
		||||
    }
 | 
			
		||||
    // 重置请求
 | 
			
		||||
    if (reset) return params;
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      ...params,
 | 
			
		||||
      pageNum: pageNum + 1,
 | 
			
		||||
      pageSize,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  async init(reset = true) {
 | 
			
		||||
    const { loadMoreStatus, commentList = [] } = this.data;
 | 
			
		||||
    const params = this.generalQueryData(reset);
 | 
			
		||||
 | 
			
		||||
    // 在加载中或者无更多数据,直接返回
 | 
			
		||||
    if (loadMoreStatus !== 0) return;
 | 
			
		||||
 | 
			
		||||
    this.setData({
 | 
			
		||||
      loadMoreStatus: 1,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      const data = await fetchComments(params, {
 | 
			
		||||
        method: 'POST',
 | 
			
		||||
      });
 | 
			
		||||
      const code = 'SUCCESS';
 | 
			
		||||
      if (code.toUpperCase() === 'SUCCESS') {
 | 
			
		||||
        const { pageList, totalCount = 0 } = data;
 | 
			
		||||
        pageList.forEach((item) => {
 | 
			
		||||
          // eslint-disable-next-line no-param-reassign
 | 
			
		||||
          item.commentTime = dayjs(Number(item.commentTime)).format(
 | 
			
		||||
            'YYYY/MM/DD HH:mm',
 | 
			
		||||
          );
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (Number(totalCount) === 0 && reset) {
 | 
			
		||||
          this.setData({
 | 
			
		||||
            commentList: [],
 | 
			
		||||
            hasLoaded: true,
 | 
			
		||||
            total: totalCount,
 | 
			
		||||
            loadMoreStatus: 2,
 | 
			
		||||
          });
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        const _commentList = reset ? pageList : commentList.concat(pageList);
 | 
			
		||||
        const _loadMoreStatus =
 | 
			
		||||
          _commentList.length === Number(totalCount) ? 2 : 0;
 | 
			
		||||
        this.setData({
 | 
			
		||||
          commentList: _commentList,
 | 
			
		||||
          pageNum: params.pageNum || 1,
 | 
			
		||||
          totalCount: Number(totalCount),
 | 
			
		||||
          loadMoreStatus: _loadMoreStatus,
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        wx.showToast({
 | 
			
		||||
          title: '查询失败,请稍候重试',
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    } catch (error) {}
 | 
			
		||||
    this.setData({
 | 
			
		||||
      hasLoaded: true,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
  getScoreArray(score) {
 | 
			
		||||
    var array = [];
 | 
			
		||||
    for (let i = 0; i < 5; i++) {
 | 
			
		||||
      if (i < score) {
 | 
			
		||||
        array.push(2);
 | 
			
		||||
      } else {
 | 
			
		||||
        array.push(0);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return array;
 | 
			
		||||
  },
 | 
			
		||||
  getComments(options) {
 | 
			
		||||
    const { commentLevel = -1, spuId, hasImage = '' } = options;
 | 
			
		||||
    if (commentLevel !== -1) {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        commentLevel: commentLevel,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    this.setData({
 | 
			
		||||
      hasImage: hasImage,
 | 
			
		||||
      commentType: hasImage ? '4' : '',
 | 
			
		||||
      spuId: spuId,
 | 
			
		||||
    });
 | 
			
		||||
    this.init(true);
 | 
			
		||||
  },
 | 
			
		||||
  changeTag(e) {
 | 
			
		||||
    var { commenttype } = e.currentTarget.dataset;
 | 
			
		||||
    var { commentType } = this.data;
 | 
			
		||||
    if (commentType === commenttype) return;
 | 
			
		||||
    this.setData({
 | 
			
		||||
      loadMoreStatus: 0,
 | 
			
		||||
      commentList: [],
 | 
			
		||||
      total: 0,
 | 
			
		||||
      myTotal: 0,
 | 
			
		||||
      myPageNum: 1,
 | 
			
		||||
      pageNum: 1,
 | 
			
		||||
    });
 | 
			
		||||
    if (commenttype === '' || commenttype === '5') {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        hasImage: '',
 | 
			
		||||
        commentLevel: '',
 | 
			
		||||
      });
 | 
			
		||||
    } else if (commenttype === '4') {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        hasImage: '1',
 | 
			
		||||
        commentLevel: '',
 | 
			
		||||
      });
 | 
			
		||||
    } else {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        hasImage: '',
 | 
			
		||||
        commentLevel: commenttype,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    if (commenttype === '5') {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        myLoadStatus: 1,
 | 
			
		||||
        commentType: commenttype,
 | 
			
		||||
      });
 | 
			
		||||
      this.getMyCommentsList();
 | 
			
		||||
    } else {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        myLoadStatus: 0,
 | 
			
		||||
        commentType: commenttype,
 | 
			
		||||
      });
 | 
			
		||||
      this.init(true);
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  onReachBottom() {
 | 
			
		||||
    const { total = 0, commentList } = this.data;
 | 
			
		||||
    if (commentList.length === total) {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        loadMoreStatus: 2,
 | 
			
		||||
      });
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.init(false);
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										8
									
								
								mini-program/pages/goods/comments/index.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								mini-program/pages/goods/comments/index.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
{
 | 
			
		||||
  "navigationBarTitleText": "全部评价",
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "t-tag": "tdesign-miniprogram/tag/tag",
 | 
			
		||||
    "comments-card": "./components/comments-card/index",
 | 
			
		||||
    "t-load-more": "/components/load-more/index"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								mini-program/pages/goods/comments/index.wxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								mini-program/pages/goods/comments/index.wxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
<view class="comments-header">
 | 
			
		||||
	<t-tag t-class="comments-header-tag {{commentType === '' ? 'comments-header-active' : ''}}" data-commentType="" bindtap="changeTag">
 | 
			
		||||
		全部({{countObj.commentCount}})
 | 
			
		||||
	</t-tag>
 | 
			
		||||
	<t-tag
 | 
			
		||||
	  t-class="comments-header-tag {{commentType === '5' ? 'comments-header-active' : ''}}"
 | 
			
		||||
	  wx:if="{{countObj.uidCount !== '0'}}"
 | 
			
		||||
	  data-commentType="5"
 | 
			
		||||
	  bindtap="changeTag"
 | 
			
		||||
	>
 | 
			
		||||
		自己({{countObj.uidCount}})
 | 
			
		||||
	</t-tag>
 | 
			
		||||
	<t-tag t-class="comments-header-tag {{commentType === '4' ? 'comments-header-active' : ''}}" data-commentType="4" bindtap="changeTag">
 | 
			
		||||
		带图({{countObj.hasImageCount}})
 | 
			
		||||
	</t-tag>
 | 
			
		||||
	<t-tag t-class="comments-header-tag {{commentType === '3' ? 'comments-header-active' : ''}}" data-commentType="3" bindtap="changeTag">
 | 
			
		||||
		好评({{countObj.goodCount}})
 | 
			
		||||
	</t-tag>
 | 
			
		||||
	<t-tag t-class="comments-header-tag {{commentType === '2' ? 'comments-header-active' : ''}}" data-commentType="2" bindtap="changeTag">
 | 
			
		||||
		中评({{countObj.middleCount}})
 | 
			
		||||
	</t-tag>
 | 
			
		||||
	<t-tag t-class="comments-header-tag {{commentType === '1' ? 'comments-header-active' : ''}}" data-commentType="1" bindtap="changeTag">
 | 
			
		||||
		差评({{countObj.badCount}})
 | 
			
		||||
	</t-tag>
 | 
			
		||||
</view>
 | 
			
		||||
<view class="comments-card-list">
 | 
			
		||||
	<block wx:for="{{commentList}}" wx:key="index">
 | 
			
		||||
		<comments-card
 | 
			
		||||
		  commentScore="{{item.commentScore}}"
 | 
			
		||||
		  userName="{{item.userName}}"
 | 
			
		||||
		  commentResources="{{item.commentResources || []}}"
 | 
			
		||||
		  commentContent="{{item.commentContent}}"
 | 
			
		||||
		  isAnonymity="{{item.isAnonymity}}"
 | 
			
		||||
		  commentTime="{{item.commentTime}}"
 | 
			
		||||
		  isAutoComment="{{item.isAutoComment}}"
 | 
			
		||||
		  userHeadUrl="{{item.userHeadUrl}}"
 | 
			
		||||
		  specInfo="{{item.specInfo}}"
 | 
			
		||||
		  sellerReply="{{item.sellerReply || ''}}"
 | 
			
		||||
		  goodsDetailInfo="{{item.goodsDetailInfo || ''}}"
 | 
			
		||||
		/>
 | 
			
		||||
	</block>
 | 
			
		||||
	<t-load-more
 | 
			
		||||
	  t-class="no-more"
 | 
			
		||||
	  status="{{loadMoreStatus}}"
 | 
			
		||||
	  no-more-text="没有更多了"
 | 
			
		||||
	  color="#BBBBBB"
 | 
			
		||||
	  failedColor="#FA550F"
 | 
			
		||||
	/>
 | 
			
		||||
</view>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										49
									
								
								mini-program/pages/goods/comments/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								mini-program/pages/goods/comments/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
/* 层级定义
 | 
			
		||||
@z-index-0: 1;
 | 
			
		||||
@z-index-1: 100;
 | 
			
		||||
@z-index-2: 200;
 | 
			
		||||
@z-index-5: 500;
 | 
			
		||||
@z-index-component: 1000; // 通用组件级别
 | 
			
		||||
@z-index-dropdown: @z-index-component;
 | 
			
		||||
@z-index-sticky: @z-index-component + 20;
 | 
			
		||||
@z-index-fixed: @z-index-component + 30;
 | 
			
		||||
@z-index-modal-backdrop:@z-index-component + 40;
 | 
			
		||||
@z-index-modal:@z-index-component + 50;
 | 
			
		||||
@z-index-popover:@z-index-component + 60;
 | 
			
		||||
@z-index-tooltip:@z-index-component + 70;
 | 
			
		||||
*/
 | 
			
		||||
/* var() css变量适配*/
 | 
			
		||||
page {
 | 
			
		||||
  background-color: #FFFFFF;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-header {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-wrap: wrap;
 | 
			
		||||
  padding: 32rpx 32rpx 0rpx;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  margin-top: -24rpx;
 | 
			
		||||
  margin-left: -24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-header-tag {
 | 
			
		||||
  margin-top: 24rpx;
 | 
			
		||||
  margin-left: 24rpx;
 | 
			
		||||
  height: 56rpx !important;
 | 
			
		||||
  font-size: 24rpx !important;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  background-color: #F5F5F5 !important;
 | 
			
		||||
  border-radius: 8rpx !important;
 | 
			
		||||
  border: 1px solid #F5F5F5 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-header-active {
 | 
			
		||||
  background-color: #FFECE9 !important;
 | 
			
		||||
  color: #FA4126 !important;
 | 
			
		||||
  border: 1px solid #FA4126 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.no-more {
 | 
			
		||||
  padding-left: 20rpx;
 | 
			
		||||
  padding-right: 20rpx;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										66
									
								
								mini-program/pages/goods/details/components/buy-bar/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								mini-program/pages/goods/details/components/buy-bar/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
Component({
 | 
			
		||||
  externalClasses: ['wr-sold-out', 'wr-class'],
 | 
			
		||||
 | 
			
		||||
  options: { multipleSlots: true },
 | 
			
		||||
 | 
			
		||||
  properties: {
 | 
			
		||||
    soldout: {
 | 
			
		||||
      // 商品是否下架
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      value: false,
 | 
			
		||||
    },
 | 
			
		||||
    jumpArray: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      value: [],
 | 
			
		||||
    },
 | 
			
		||||
    isStock: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      value: true,
 | 
			
		||||
    }, // 是否有库存
 | 
			
		||||
    isSlotButton: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      value: false,
 | 
			
		||||
    }, // 是否开启按钮插槽
 | 
			
		||||
    shopCartNum: {
 | 
			
		||||
      type: Number, // 购物车气泡数量
 | 
			
		||||
    },
 | 
			
		||||
    buttonType: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      value: 0,
 | 
			
		||||
    },
 | 
			
		||||
    minDiscountPrice: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
    minSalePrice: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  data: {
 | 
			
		||||
    fillPrice: false,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    toAddCart() {
 | 
			
		||||
      const { isStock } = this.properties;
 | 
			
		||||
      if (!isStock) return;
 | 
			
		||||
      this.triggerEvent('toAddCart');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    toBuyNow(e) {
 | 
			
		||||
      const { isStock } = this.properties;
 | 
			
		||||
      if (!isStock) return;
 | 
			
		||||
      this.triggerEvent('toBuyNow', e);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    toNav(e) {
 | 
			
		||||
      const { url } = e.currentTarget.dataset;
 | 
			
		||||
      return this.triggerEvent('toNav', {
 | 
			
		||||
        e,
 | 
			
		||||
        url,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "component": true,
 | 
			
		||||
    "usingComponents": {
 | 
			
		||||
        "t-icon": "tdesign-miniprogram/icon/icon"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,38 @@
 | 
			
		||||
<view class="flex soldout flex-center wr-sold-out" wx:if="{{soldout ||  !isStock}}">
 | 
			
		||||
	{{soldout ? '商品已下架' : '商品已售馨'}}
 | 
			
		||||
</view>
 | 
			
		||||
<view class="footer-cont flex flex-between wr-class">
 | 
			
		||||
	<view class="flex flex-between bottom-operate-left" wx:if="{{jumpArray.length > 0}}">
 | 
			
		||||
		<view
 | 
			
		||||
		  wx:for="{{jumpArray}}"
 | 
			
		||||
		  wx:key="index"
 | 
			
		||||
		  class="icon-warp operate-wrap"
 | 
			
		||||
		  bindtap="toNav"
 | 
			
		||||
		  data-ele="foot_navigation"
 | 
			
		||||
		  data-index="{{index}}"
 | 
			
		||||
		  data-url="{{item.url}}"
 | 
			
		||||
		>
 | 
			
		||||
			<view>
 | 
			
		||||
				<text wx:if="{{shopCartNum > 0 && item.showCartNum}}" class="tag-cart-num">
 | 
			
		||||
					{{shopCartNum > 99 ? '99+' : shopCartNum}}
 | 
			
		||||
				</text>
 | 
			
		||||
				<t-icon prefix="wr" name="{{item.iconName}}" size="40rpx" />
 | 
			
		||||
				<view class="operate-text">{{item.title}}</view>
 | 
			
		||||
			</view>
 | 
			
		||||
		</view>
 | 
			
		||||
	</view>
 | 
			
		||||
	<block wx:if="{{buttonType === 1}}">
 | 
			
		||||
		<view class="flex buy-buttons">
 | 
			
		||||
			<view class="bar-separately {{soldout || !isStock ? 'bar-addCart-disabled' : ''}}" bindtap="toAddCart">
 | 
			
		||||
				加入购物车
 | 
			
		||||
			</view>
 | 
			
		||||
			<view class="bar-buy {{soldout || !isStock ? 'bar-buyNow-disabled' : ''}}" bindtap="toBuyNow">
 | 
			
		||||
				立即购买
 | 
			
		||||
			</view>
 | 
			
		||||
		</view>
 | 
			
		||||
	</block>
 | 
			
		||||
	<block wx:if="{{isSlotButton}}">
 | 
			
		||||
		<slot name="buyButton" />
 | 
			
		||||
	</block>
 | 
			
		||||
</view>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										107
									
								
								mini-program/pages/goods/details/components/buy-bar/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								mini-program/pages/goods/details/components/buy-bar/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
			
		||||
.footer-cont {
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  padding: 16rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.icon-warp {
 | 
			
		||||
  width: 110rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.operate-wrap {
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bottom-operate-left {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bottom-operate-left .icon-warp {
 | 
			
		||||
  width: 50%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tag-cart-num {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  left: 50rpx;
 | 
			
		||||
  right: auto;
 | 
			
		||||
  top: 6rpx;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  line-height: 24rpx;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  z-index: 99;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
  min-width: 28rpx;
 | 
			
		||||
  border-radius: 14rpx;
 | 
			
		||||
  background-color: #fa550f !important;
 | 
			
		||||
  font-size: 20rpx;
 | 
			
		||||
  font-weight: 400;
 | 
			
		||||
  padding: 2rpx 6rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.operate-text {
 | 
			
		||||
  color: #666;
 | 
			
		||||
  font-size: 20rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.soldout {
 | 
			
		||||
  height: 80rpx;
 | 
			
		||||
  background: rgba(170, 170, 170, 1);
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.addCart-disabled,
 | 
			
		||||
.bar-addCart-disabled {
 | 
			
		||||
  background: rgba(221, 221, 221, 1) !important;
 | 
			
		||||
  color: #fff !important;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.buyNow-disabled,
 | 
			
		||||
.bar-buyNow-disabled {
 | 
			
		||||
  background: rgba(198, 198, 198, 1) !important;
 | 
			
		||||
  color: #fff !important;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bar-separately,
 | 
			
		||||
.bar-buy {
 | 
			
		||||
  width: 254rpx;
 | 
			
		||||
  height: 80rpx;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bar-separately {
 | 
			
		||||
  background: #ffece9;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
  border-radius: 40rpx 0 0 40rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bar-buy {
 | 
			
		||||
  background-color: #fa4126;
 | 
			
		||||
  border-radius: 0rpx 40rpx 40rpx 0rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  display: -webkit-flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex-center {
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  -webkit-justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  -webkit-align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex-between {
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  -webkit-justify-content: space-between;
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user