Initial commit

This commit is contained in:
sjk
2025-11-17 13:32:54 +08:00
commit e788eab6eb
1659 changed files with 171560 additions and 0 deletions

View File

@@ -0,0 +1,74 @@
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: '',
},
isFavorite: {
type: Boolean,
value: false,
},
},
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,
});
},
onToggleFavorite() {
this.triggerEvent('onToggleFavorite');
},
},
});

View File

@@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"t-icon": "tdesign-miniprogram/icon/icon"
}
}

View File

@@ -0,0 +1,44 @@
<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 class="icon-warp operate-wrap favorite-wrap" bindtap="onToggleFavorite">
<view>
<t-icon name="{{isFavorite ? 'heart-filled' : 'heart'}}" size="40rpx" color="{{isFavorite ? '#ff4757' : '#666'}}" />
<view class="operate-text">{{isFavorite ? '已收藏' : '收藏'}}</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>

View File

@@ -0,0 +1,181 @@
.footer-cont {
background-color: #fff;
padding: 12rpx 12rpx calc(env(safe-area-inset-bottom) + 12rpx) 12rpx;
display: flex;
align-items: center;
gap: 20rpx;
position: sticky;
bottom: 0;
left: 0;
right: 0;
z-index: 10;
box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.05);
box-sizing: border-box;
}
.icon-warp {
width: 100rpx;
height: 80rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
background: #f8f8f8;
border-radius: 16rpx;
border: 1rpx solid #f0f0f0;
transition: all 0.3s ease;
}
.icon-warp:active {
background: #f0f0f0;
transform: scale(0.95);
}
.operate-wrap {
position: relative;
flex: 1;
}
.bottom-operate-left {
display: flex;
gap: 12rpx;
flex: none;
min-width: 0;
}
.bottom-operate-left .icon-warp {
width: 100rpx;
flex: none;
}
.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;
margin-top: 4rpx;
font-weight: 400;
}
.soldout {
height: 80rpx;
background: linear-gradient(135deg, #ccc 0%, #aaa 100%);
width: 100%;
color: #fff;
border-radius: 16rpx;
font-size: 28rpx;
font-weight: 500;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.addCart-disabled,
.bar-addCart-disabled {
background: linear-gradient(135deg, #ddd 0%, #ccc 100%) !important;
color: #fff !important;
font-size: 28rpx;
border-radius: 16rpx 0 0 16rpx !important;
}
.buyNow-disabled,
.bar-buyNow-disabled {
background: linear-gradient(135deg, #ccc 0%, #aaa 100%) !important;
color: #fff !important;
font-size: 28rpx;
border-radius: 0 16rpx 16rpx 0 !important;
}
.bar-separately,
.bar-buy {
height: 80rpx;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
font-weight: 500;
transition: all 0.3s ease;
box-shadow: 0 4rpx 12rpx rgba(250, 65, 38, 0.2);
flex: 1 1 auto;
min-width: 160rpx;
box-sizing: border-box;
}
.bar-separately {
background: linear-gradient(135deg, #fff5f4 0%, #ffece9 100%);
color: #fa4126;
border-radius: 16rpx 0 0 16rpx;
border: 2rpx solid #fa4126;
box-shadow: 0 4rpx 12rpx rgba(250, 65, 38, 0.1);
}
.bar-separately:active {
background: linear-gradient(135deg, #ffece9 0%, #ffe0dc 100%);
transform: scale(0.98);
}
.bar-buy {
background: linear-gradient(135deg, #fa4126 0%, #e63312 100%);
border-radius: 0 16rpx 16rpx 0;
}
.bar-buy:active {
background: linear-gradient(135deg, #e63312 0%, #d12a0f 100%);
transform: scale(0.98);
}
/* 收藏按钮样式 */
.favorite-wrap {
position: relative;
}
.favorite-wrap .operate-text {
color: #666;
transition: color 0.3s ease;
}
.favorite-wrap:active .operate-text {
color: #ff4757;
}
.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;
}
/* 购买按钮容器自适应剩余空间 */
.buy-buttons {
display: flex;
gap: 0;
flex: 1 1 auto;
min-width: 0;
}

View File

@@ -0,0 +1,364 @@
/* eslint-disable no-param-reassign */
/* eslint-disable no-nested-ternary */
import Toast from 'tdesign-miniprogram/toast/index';
Component({
options: {
multipleSlots: true,
addGlobalClass: true,
},
properties: {
src: {
type: String,
},
title: String,
show: {
type: Boolean,
value: false,
},
limitBuyInfo: {
type: String,
value: '',
},
isStock: {
type: Boolean,
value: true,
},
limitMaxCount: {
type: Number,
value: 999,
},
limitMinCount: {
type: Number,
value: 1,
},
skuList: {
type: Array,
value: [],
observer(skuList) {
if (skuList && skuList.length > 0) {
if (this.initStatus) {
this.initData();
}
}
},
},
specList: {
type: Array,
value: [],
observer(specList) {
if (specList && specList.length > 0) {
this.initData();
}
},
},
outOperateStatus: {
type: Boolean,
value: false,
},
hasAuth: {
type: Boolean,
value: false,
},
count: {
type: Number,
value: 1,
observer(count) {
this.setData({
buyNum: count,
});
},
},
},
initStatus: false,
selectedSku: {},
selectSpecObj: {},
data: {
buyNum: 1,
isAllSelectedSku: false,
},
methods: {
initData() {
const { skuList } = this.properties;
const { specList } = this.properties;
// 为每个规格值计算库存信息
specList.forEach((item) => {
if (item.specValueList.length > 0) {
item.specValueList.forEach((subItem) => {
const obj = this.checkSkuStockQuantity(subItem, skuList, item);
subItem.hasStockObj = obj;
// 初始化未选中状态
subItem.isSelected = false;
});
}
});
// 默认选择策略优先选择第一个有库存的SKU组合其次选择第一个SKU
const getQty = (sku) => {
return Number((sku.stockInfo && sku.stockInfo.stockQuantity) ?? sku.stock ?? sku.quantity ?? 0) || 0;
};
const defaultSku = (skuList || []).find((s) => getQty(s) > 0) || (skuList || [])[0];
// 构建 selectedSku 映射,并在 specList 中标记选中项
const selectedSkuMap = {};
if (defaultSku && Array.isArray(defaultSku.specInfo)) {
defaultSku.specInfo.forEach((spec) => {
const specId = spec.specId;
const specValueId = spec.specValueId;
const specTitle = spec.specTitle;
const specValue = spec.specValue;
// 在对应的规格组内标记选中项
specList.forEach((group) => {
const sameGroup = String(group.specId) === String(specId) || (!!specTitle && group.title === specTitle);
if (sameGroup && Array.isArray(group.specValueList)) {
group.specValueList.forEach((sv) => {
const matchById = specValueId != null && String(sv.specValueId) === String(specValueId);
const matchByText = specValue != null && sv.specValue != null && sv.specValue === specValue;
sv.isSelected = matchById || matchByText;
});
// 记录所选项的ID优先使用ID
const chosen = group.specValueList.find((sv) => sv.isSelected);
if (chosen) {
selectedSkuMap[group.specId] = chosen.specValueId;
}
}
});
});
} else {
// 当没有SKU或SKU缺少specInfo时退化为每组选择第一个有库存的规格值
specList.forEach((group) => {
const firstAvailable = (group.specValueList || []).find((sv) => sv.hasStockObj?.hasStock) || (group.specValueList || [])[0];
if (firstAvailable) {
group.specValueList.forEach((sv) => { sv.isSelected = sv === firstAvailable; });
selectedSkuMap[group.specId] = firstAvailable.specValueId;
}
});
}
// 更新组件状态
const isAllSelectedSku = specList.every((spec) => !!selectedSkuMap[spec.specId]);
this.selectedSku = selectedSkuMap;
this.selectSpecObj = {};
this.setData({
specList,
isAllSelectedSku,
});
// 通知父页面已完成默认选择,便于价格与图片联动
this.triggerEvent('change', {
selectedSku: this.selectedSku,
isAllSelectedSku,
});
this.initStatus = true;
},
// 兼容两种数据结构:
// 1) sku.specInfo 使用 { specId, specValueId }
// 2) sku.specInfo 使用 { specTitle, specValue }
// 同时 specList.subItem 具备 { specValueId, specValue }
checkSkuStockQuantity(specValueItem, skuList, specGroupItem) {
let hasStock = false;
let stockQuantity = 0;
skuList.forEach((sku) => {
if (sku.specInfo) {
sku.specInfo.forEach((spec) => {
// 统一以字符串比较,避免类型不一致导致匹配失败
const matchById =
spec.specValueId != null && specValueItem.specValueId != null &&
String(spec.specValueId) === String(specValueItem.specValueId);
const sameGroupByTitle =
spec.specTitle && specGroupItem && specGroupItem.title && spec.specTitle === specGroupItem.title;
const matchByText =
spec.specValue != null && specValueItem.specValue != null && spec.specValue === specValueItem.specValue &&
(sameGroupByTitle || true); // 若无 title 也放行文本匹配
if (matchById || matchByText) {
// 兼容多种库存字段来源,优先 stockInfo.stockQuantity
const qty = Number(
(sku.stockInfo && sku.stockInfo.stockQuantity) ?? sku.stock ?? sku.quantity ?? 0
) || 0;
stockQuantity += qty;
if (qty > 0) {
hasStock = true;
}
}
});
}
});
return {
hasStock,
stockQuantity,
};
},
toChooseItem(e) {
const { specid, id, val } = e.currentTarget.dataset;
// 放开点击,避免因错误的 hasStock 计算而阻断选择
const { specList } = this.data;
const { skuList } = this.properties;
specList.forEach((spec) => {
if (String(spec.specId) === String(specid)) {
spec.specValueList.forEach((specValue) => {
if (String(specValue.specValueId) === String(id)) {
specValue.isSelected = !specValue.isSelected;
} else {
specValue.isSelected = false;
}
});
}
});
this.selectSpecObj[specid] = {
specId: specid,
specValueId: id,
specValue: val,
};
this.selectedSku[specid] = id;
const isAllSelectedSku = this.isAllSelectedSku();
this.setData({
specList,
isAllSelectedSku,
});
// 与父页面绑定的事件名保持一致:父页面使用 bind:change="chooseSpecItem"
this.triggerEvent('change', {
selectedSku: this.selectedSku,
isAllSelectedSku,
});
},
isAllSelectedSku() {
const { specList } = this.properties;
let isAllSelectedSku = true;
specList.forEach((spec) => {
if (!this.selectedSku[spec.specId]) {
isAllSelectedSku = false;
}
});
return isAllSelectedSku;
},
getSelectedSkuId() {
const { skuList } = this.properties;
const { selectedSku } = this;
let selectedSkuId = '';
skuList.forEach((sku) => {
let isMatch = true;
if (sku.specInfo) {
sku.specInfo.forEach((spec) => {
// 统一字符串比较避免类型不一致导致匹配失败
if (String(selectedSku[spec.specId]) !== String(spec.specValueId)) {
isMatch = false;
}
});
}
if (isMatch) {
selectedSkuId = sku.skuId;
}
});
return selectedSkuId;
},
handlePopupHide() {
// 触发与父页面绑定一致的事件名,确保可以关闭弹窗
this.triggerEvent('closeSpecsPopup');
},
specsConfirm() {
const { isAllSelectedSku } = this.data;
if (!isAllSelectedSku) {
Toast({
context: this,
selector: '#t-toast',
message: '请选择完整的商品规格',
theme: 'warning',
direction: 'column',
});
return;
}
this.triggerEvent('specsConfirm', {
selectedSku: this.selectedSku,
buyNum: this.data.buyNum,
});
},
addCart() {
const { isAllSelectedSku } = this.data;
if (!isAllSelectedSku) {
Toast({
context: this,
selector: '#t-toast',
message: '请选择完整的商品规格',
theme: 'warning',
direction: 'column',
});
return;
}
this.triggerEvent('addCart', {
selectedSku: this.selectedSku,
buyNum: this.data.buyNum,
});
},
buyNow() {
const { isAllSelectedSku } = this.data;
if (!isAllSelectedSku) {
Toast({
context: this,
selector: '#t-toast',
message: '请选择完整的商品规格',
theme: 'warning',
direction: 'column',
});
return;
}
this.triggerEvent('buyNow', {
selectedSku: this.selectedSku,
buyNum: this.data.buyNum,
});
},
setBuyNum(e) {
const { value } = e.detail;
this.setData({
buyNum: value,
});
},
changeNum(e) {
const { buyNum } = e.detail;
this.setData({
buyNum,
});
},
handleBuyNumChange(e) {
const { value } = e.detail;
this.setData({
buyNum: value,
});
// 触发父组件的 changeNum 事件,通知价格更新
this.triggerEvent('changeNum', {
buyNum: value,
});
},
},
});

View File

@@ -0,0 +1,10 @@
{
"component": true,
"usingComponents": {
"t-popup": "tdesign-miniprogram/popup/popup",
"t-icon": "tdesign-miniprogram/icon/icon",
"t-image": "/components/webp-image/index",
"t-stepper": "tdesign-miniprogram/stepper/stepper",
"t-toast": "tdesign-miniprogram/toast/toast"
}
}

View File

@@ -0,0 +1,84 @@
<t-popup visible="{{show}}" placement="bottom" bind:visible-change="handlePopupHide">
<view class="popup-container">
<view class="popup-close" bindtap="handlePopupHide">
<t-icon name="close" size="36rpx" />
</view>
<view class="popup-sku-header">
<t-image t-class="popup-sku-header__img" src="{{src}}" />
<view class="popup-sku-header__goods-info">
<view class="popup-sku__goods-name">{{title}}</view>
<view class="goods-price-container">
<slot name="goods-price" />
</view>
<!-- 已选规格 -->
<view class="popup-sku__selected-spec">
<view>选择:</view>
<view wx:for="{{specList}}" wx:key="specId">
<view
class="popup-sku__selected-item"
wx:for="{{item.specValueList}}"
wx:for-item="selectedItem"
wx:if="{{selectedItem.isSelected}}"
wx:key="specValueId"
>
{{selectedItem.specValue}}
</view>
</view>
</view>
</view>
</view>
<view class="popup-sku-body">
<view class="popup-sku-group-container">
<view class="popup-sku-row" wx:for="{{specList}}" wx:key="specId">
<view class="popup-sku-row__title">{{item.title}}</view>
<block
wx:for="{{item.specValueList}}"
wx:for-item="valuesItem"
wx:for-index="valuesIndex"
wx:key="specValueId"
>
<view
class="popup-sku-row__item {{valuesItem.isSelected ? 'popup-sku-row__item--active' : ''}} {{!valuesItem.hasStockObj.hasStock || !isStock ? 'disabled-sku-selected' : ''}}"
data-specid="{{item.specId}}"
data-id="{{valuesItem.specValueId}}"
data-val="{{valuesItem.specValue}}"
data-hasStock="{{valuesItem.hasStockObj.hasStock}}"
bindtap="toChooseItem"
>
{{valuesItem.specValue}}
</view>
</block>
</view>
</view>
<view class="popup-sku-stepper-stock">
<view class="popup-sku-stepper-container">
<view class="popup-sku__stepper-title">
购买数量
<view class="limit-text" wx:if="{{limitBuyInfo}}"> ({{limitBuyInfo}}) </view>
</view>
<t-stepper value="{{buyNum}}" min="{{1}}" max="{{2}}" theme="filled" bind:change="handleBuyNumChange" />
</view>
</view>
</view>
<view wx:if="{{outOperateStatus}}" class="single-confirm-btn {{!isStock ? 'disabled' : ''}}" bindtap="specsConfirm">
确定
</view>
<view
class="popup-sku-actions flex flex-between {{!isStock ? 'popup-sku-disabled' : ''}}"
wx:if="{{!outOperateStatus}}"
>
<view class="sku-operate">
<view class="selected-sku-btn sku-operate-addCart {{!isStock ? 'disabled' : ''}}" bindtap="addCart">
加入购物车
</view>
</view>
<view class="sku-operate">
<view class="selected-sku-btn sku-operate-buyNow {{!isStock ? 'disabled' : ''}}" bindtap="buyNow">
立即购买
</view>
</view>
</view>
<slot name="bottomSlot" />
</view>
</t-popup>
<t-toast id="t-toast" />

View File

@@ -0,0 +1,312 @@
.popup-container {
background-color: #ffffff;
position: relative;
z-index: 100;
border-radius: 16rpx 16rpx 0 0;
padding-bottom: calc(env(safe-area-inset-bottom) + 20rpx);
}
.popup-container .popup-close {
position: absolute;
right: 30rpx;
top: 30rpx;
z-index: 9;
color: #999999;
}
.popup-sku-header {
display: flex;
padding: 30rpx 28rpx 0 30rpx;
}
.popup-sku-header .popup-sku-header__img {
width: 176rpx;
height: 176rpx;
border-radius: 8rpx;
background: #d8d8d8;
margin-right: 24rpx;
}
.popup-sku-header .popup-sku-header__goods-info {
position: relative;
width: 500rpx;
}
.popup-sku-header .popup-sku-header__goods-info .popup-sku__goods-name {
font-size: 28rpx;
line-height: 40rpx;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
white-space: normal;
overflow: hidden;
width: 430rpx;
text-overflow: ellipsis;
}
.popup-sku-header .popup-sku-header__goods-info .popup-sku__selected-spec {
display: flex;
color: #333333;
font-size: 26rpx;
line-height: 36rpx;
}
.popup-sku__total-price {
display: flex;
align-items: center;
margin-top: 8rpx;
font-size: 24rpx;
color: #666666;
}
.popup-sku__total-price .total-price-label {
margin-right: 8rpx;
}
.popup-sku-header
.popup-sku-header__goods-info
.popup-sku__selected-spec
.popup-sku__selected-item {
margin-right: 10rpx;
}
.popup-sku-body {
margin: 0 30rpx 40rpx;
max-height: 600rpx;
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
.popup-sku-body .popup-sku-group-container .popup-sku-row {
padding: 32rpx 0;
border-bottom: 1rpx solid #f5f5f5;
}
.popup-sku-body
.popup-sku-group-container
.popup-sku-row
.popup-sku-row__title {
font-size: 26rpx;
color: #333;
}
.popup-sku-body .popup-sku-group-container .popup-sku-row .popup-sku-row__item {
font-size: 24rpx;
color: #333;
min-width: 128rpx;
height: 56rpx;
background-color: #f5f5f5;
border-radius: 8rpx;
border: 2rpx solid #f5f5f5;
margin: 19rpx 26rpx 0 0;
padding: 0 16rpx;
display: inline-flex;
align-items: center;
justify-content: center;
}
.popup-sku-body
.popup-sku-group-container
.popup-sku-row
.popup-sku-row__item.popup-sku-row__item--active {
border: 2rpx solid #fa4126;
color: #fa4126;
background: rgba(255, 95, 21, 0.04);
}
.popup-sku-body
.popup-sku-group-container
.popup-sku-row
.disabled-sku-selected {
background: #f5f5f5 !important;
color: #cccccc;
}
.popup-sku-body .popup-sku-stepper-stock .popup-sku-stepper-container {
display: flex;
align-items: center;
justify-content: space-between;
margin: 40rpx 0;
}
.popup-sku-body
.popup-sku-stepper-stock
.popup-sku-stepper-container
.popup-sku__stepper-title {
display: flex;
font-size: 26rpx;
color: #333;
}
.popup-sku-body
.popup-sku-stepper-stock
.popup-sku-stepper-container
.popup-sku__stepper-title
.limit-text {
margin-left: 10rpx;
color: #999999;
}
.popup-sku-body
.popup-sku-stepper-stock
.popup-sku-stepper-container
.popup-stepper {
display: flex;
flex-flow: row nowrap;
align-items: center;
font-size: 28px;
height: 48rpx;
line-height: 62rpx;
}
.popup-sku-body
.popup-sku-stepper-stock
.popup-sku-stepper-container
.popup-stepper
.input-btn,
.popup-sku-body
.popup-sku-stepper-stock
.popup-sku-stepper-container
.popup-stepper
.input-num-wrap {
position: relative;
height: 100%;
text-align: center;
background-color: #f5f5f5;
border-radius: 4rpx;
}
.popup-sku-body
.popup-sku-stepper-stock
.popup-sku-stepper-container
.popup-stepper
.input-num-wrap {
color: #282828;
display: flex;
max-width: 76rpx;
align-items: center;
justify-content: space-between;
}
.popup-sku-body
.popup-sku-stepper-stock
.popup-sku-stepper-container
.popup-stepper
.input-num-wrap
.input-num {
height: 100%;
width: auto;
font-weight: 600;
font-size: 30rpx;
}
.popup-sku-body
.popup-sku-stepper-stock
.popup-sku-stepper-container
.popup-stepper
.input-btn {
width: 48rpx;
}
.popup-sku-body
.popup-sku-stepper-stock
.popup-sku-stepper-container
.popup-stepper
.popup-stepper__minus {
margin-right: 4rpx;
border-radius: 4rpx;
color: #9a979b;
display: flex;
align-items: center;
justify-content: center;
}
.popup-sku-body
.popup-sku-stepper-stock
.popup-sku-stepper-container
.popup-stepper
.popup-stepper__plus {
margin-left: 4rpx;
border-radius: 4rpx;
color: #9a979b;
display: flex;
align-items: center;
justify-content: center;
}
.popup-sku-body
.popup-sku-stepper-stock
.popup-sku-stepper-container
.popup-stepper
.popup-stepper__plus::after {
width: 24rpx;
height: 3rpx;
background-color: #999999;
}
.popup-sku-body
.popup-sku-stepper-stock
.popup-sku-stepper-container
.popup-stepper
.popup-stepper__plus::before {
width: 3rpx;
height: 24rpx;
background-color: #999999;
}
.popup-sku-actions {
font-size: 32rpx;
height: 80rpx;
text-align: center;
line-height: 80rpx;
padding: 0 20rpx;
}
.popup-sku-actions .sku-operate {
height: 80rpx;
width: 50%;
color: #fff;
border-radius: 48rpx;
}
.popup-sku-actions .sku-operate .sku-operate-addCart {
background-color: #ffece9;
color: #fa4126;
border-radius: 48rpx 0 0 48rpx;
}
.popup-sku-actions .sku-operate .sku-operate-addCart.disabled {
background: rgb(221, 221, 221);
color: #fff;
}
.popup-sku-actions .sku-operate .sku-operate-buyNow {
background-color: #fa4126;
border-radius: 0 48rpx 48rpx 0;
}
.popup-sku-actions .sku-operate .sku-operate-buyNow.disabled {
color: #fff;
background: rgb(198, 198, 198);
}
.popup-sku-actions .sku-operate .selected-sku-btn {
width: 100%;
}
.popup-container .single-confirm-btn {
border-radius: 48rpx;
color: #ffffff;
margin: 0 32rpx;
font-size: 32rpx;
height: 80rpx;
text-align: center;
line-height: 88rpx;
background-color: #fa4126;
}
.popup-container .single-confirm-btn.disabled {
font-size: 32rpx;
color: #fff;
background-color: #dddddd;
}

View File

@@ -0,0 +1,35 @@
Component({
options: {
multipleSlots: true,
},
properties: {
list: Array,
title: {
type: String,
value: '促销说明',
},
show: {
type: Boolean,
},
},
// data: {
// list: [],
// },
methods: {
change(e) {
const { index } = e.currentTarget.dataset;
this.triggerEvent('promotionChange', {
index,
});
},
closePromotionPopup() {
this.triggerEvent('closePromotionPopup', {
show: false,
});
},
},
});

View File

@@ -0,0 +1,7 @@
{
"component": true,
"usingComponents": {
"t-popup": "tdesign-miniprogram/popup/popup",
"t-icon": "tdesign-miniprogram/icon/icon"
}
}

View File

@@ -0,0 +1,34 @@
<t-popup visible="{{show}}" placement="bottom" bind:visible-change="closePromotionPopup">
<view class="promotion-popup-container">
<view class="promotion-popup-close" bindtap="closePromotionPopup">
<t-icon name="close" size="36rpx" />
</view>
<view class="promotion-popup-title">
<view class="title">{{title}}</view>
</view>
<view class="promotion-popup-content">
<view class="promotion-detail-list">
<view
class="list-item"
wx:for="{{list}}"
wx:key="index"
bindtap="change"
data-index="{{index}}"
>
<view class="tag">{{item.tag}}</view>
<view class="content">
<text class="list-content">{{item.label ? item.label : ''}}</text>
</view>
<t-icon
class="collect-btn"
name="chevron-right"
size="40rpx"
color="#bbb"
/>
</view>
</view>
</view>
<slot name="promotion-bottom" />
</view>
</t-popup>

View File

@@ -0,0 +1,131 @@
.promotion-popup-container {
background-color: #ffffff;
position: relative;
z-index: 100;
border-radius: 16rpx 16rpx 0 0;
}
.promotion-popup-container .promotion-popup-close {
position: absolute;
right: 30rpx;
top: 30rpx;
z-index: 9;
color: rgba(153, 153, 153, 1);
}
.promotion-popup-container .promotion-popup-close .market {
font-size: 25rpx;
color: #999;
}
.promotion-popup-container .promotion-popup-title {
height: 100rpx;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.promotion-popup-container .promotion-popup-title {
font-size: 32rpx;
color: #222427;
font-weight: 600;
}
.promotion-popup-container .promotion-popup-content {
min-height: 400rpx;
max-height: 600rpx;
padding-bottom: calc(env(safe-area-inset-bottom) + 20rpx);
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
.promotion-popup-container .promotion-popup-content .promotion-detail-list {
margin: 0 30rpx;
}
.promotion-popup-container
.promotion-popup-content
.promotion-detail-list
.list-item:last-child {
margin-bottom: env(safe-area-inset-bottom);
border-bottom: 0;
padding-bottom: calc(28rpx + env(safe-area-inset-bottom));
}
.promotion-popup-container
.promotion-popup-content
.promotion-detail-list
.list-item {
display: flex;
justify-content: space-between;
padding: 10rpx 0 28rpx;
position: relative;
font-size: 24rpx;
color: #222427;
}
.promotion-popup-container
.promotion-popup-content
.promotion-detail-list
.list-item
.tag {
box-sizing: border-box;
font-size: 20rpx;
line-height: 32rpx;
padding: 2rpx 12rpx;
background-color: #ffece9;
margin-right: 16rpx;
display: inline-flex;
color: #fa4126;
border-radius: 54rpx;
flex-shrink: 0;
position: relative;
top: 2rpx;
}
.promotion-popup-container
.promotion-popup-content
.promotion-detail-list
.list-item
.content {
font-size: 28rpx;
color: #222427;
flex: 1;
line-height: 40rpx;
display: flex;
}
.promotion-popup-container
.promotion-popup-content
.promotion-detail-list
.list-item
.content
.list-content {
width: 440rpx;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
display: inline-block;
}
.promotion-popup-container
.promotion-popup-content
.promotion-detail-list
.list-item
.collect-btn {
font-size: 24rpx;
flex-shrink: 0;
margin-left: 20rpx;
display: flex;
align-items: center;
}
.promotion-popup-container
.promotion-popup-content
.promotion-detail-list
.list-item
.collect-btn
.linkText {
margin-right: 8rpx;
}