- 从 main 获取 single_uniapp22miao 子项目 - dart-sass: /deep/ -> ::v-deep,calc 运算符加空格 - DEPLOY.md 采用 shccd159 版本(4 子项目架构说明) Made-with: Cursor
850 lines
21 KiB
Vue
850 lines
21 KiB
Vue
<template>
|
||
<view class="goods-detail">
|
||
<!-- 顶部导航栏 -->
|
||
<view class="nav-bar">
|
||
<view class="nav-back" @click="goBack">
|
||
<text class="iconfont icon-fanhui"></text>
|
||
</view>
|
||
<text class="nav-title">商品详情</text>
|
||
<view class="nav-right"></view>
|
||
</view>
|
||
|
||
<!-- 商品图片轮播 -->
|
||
<swiper
|
||
class="goods-swiper"
|
||
:indicator-dots="true"
|
||
indicator-color="rgba(0,0,0,0.3)"
|
||
indicator-active-color="#FF4D4F"
|
||
>
|
||
<swiper-item v-for="(image, index) in sliderImage" :key="index">
|
||
<image
|
||
:src="image"
|
||
class="swiper-image"
|
||
mode="aspectFill"
|
||
@click="previewImage(index)"
|
||
/>
|
||
</swiper-item>
|
||
</swiper>
|
||
|
||
<!-- 商品信息 -->
|
||
<view class="wrapper" v-if="attr.productSelect">
|
||
<view class="share-section">
|
||
<view class="money-box">
|
||
<text class="points-symbol">积分</text>
|
||
<text class="points-num">{{ attr.productSelect.price || 0 }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="introduce">{{ productInfo.storeName }}</view>
|
||
|
||
<!-- <view class="label">
|
||
<view>原价:¥{{ attr.productSelect.otPrice || 0 }}</view>
|
||
<view>库存:{{ attr.productSelect.stock || 0 }}{{ productInfo.unitName }}</view>
|
||
<view>销量:{{ Number(productInfo.sales) + Number(productInfo.ficti) }}{{ productInfo.unitName }}</view>
|
||
</view> -->
|
||
</view>
|
||
|
||
<!-- 规格选择 -->
|
||
<view class="attribute" @click="selecAttr">
|
||
<view class="attr-row">
|
||
<view class="attr-text">{{attrTxt}}:<text class="selected-attr">{{attrValue}}</text></view>
|
||
<view class="iconfont icon-jiantou arrow-right"></view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 属性选择组件 -->
|
||
<productWindow
|
||
:attr="attr"
|
||
:isShow='1'
|
||
:iSplus='1'
|
||
@myevent="onMyEvent"
|
||
@ChangeAttr="ChangeAttr"
|
||
@ChangeCartNum="ChangeCartNum"
|
||
@attrVal="attrVal"
|
||
@iptCartNum="iptCartNum">
|
||
</productWindow>
|
||
|
||
<!-- 商品详情 -->
|
||
<view class="detail-section">
|
||
<view class="detail-info-list" v-if="attr.productSelect">
|
||
<view class="detail-item">库存:{{ attr.productSelect.stock || 0 }}件</view>
|
||
<!-- <view class="detail-item">已兑换:{{ Number(productInfo.sales) + Number(productInfo.ficti) }}件</view> -->
|
||
</view>
|
||
<view class="detail-content">
|
||
<rich-text :nodes="description" />
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 浮动购物车按钮 -->
|
||
<view class="floating-cart animated" :class="animated ? 'bounceIn' : ''" @click="goToCart">
|
||
<view class='iconfont icon-gouwuche1'>
|
||
<text v-if="Math.floor(CartCount) > 0" class='cart-badge'>{{CartCount}}</text>
|
||
</view>
|
||
<!-- <view class="cart-text">购物车</view> -->
|
||
</view>
|
||
|
||
<!-- 底部操作栏 -->
|
||
<view class="bottom-bar safe-area-inset-bottom">
|
||
<view class="btn-group">
|
||
<view class="btn-cart" @click="onCartAdd">
|
||
<text>加入购物车</text>
|
||
</view>
|
||
<view
|
||
class="btn-buy"
|
||
:class="{ disabled: attr.productSelect && attr.productSelect.stock <= 0 }"
|
||
@click="onExchange"
|
||
>
|
||
<text>{{ exchangeButtonText }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import { collectIntegralGoods } from '@/api/miao.js'
|
||
import { getProductDetail, postCartAdd } from '@/api/store.js';
|
||
import { getCartCounts } from '@/api/order.js';
|
||
import { toLogin } from '@/libs/login.js';
|
||
import { mapGetters } from "vuex";
|
||
import productWindow from '@/components/productWindow';
|
||
|
||
export default {
|
||
components: {
|
||
productWindow
|
||
},
|
||
|
||
data() {
|
||
return {
|
||
goodsId: 0,
|
||
productInfo: {
|
||
sales: 0,
|
||
ficti: 0,
|
||
unitName: '件'
|
||
},
|
||
productValue: {},
|
||
skuArr: [],
|
||
sliderImage: [],
|
||
attr: {
|
||
cartAttr: false,
|
||
productAttr: [],
|
||
productSelect: {
|
||
price: 0,
|
||
stock: 0,
|
||
otPrice: 0,
|
||
unique: '',
|
||
cart_num: 1
|
||
}
|
||
},
|
||
attrValue: '',
|
||
attrTxt: '请选择',
|
||
reply: [],
|
||
replyCount: 0,
|
||
replyChance: 0,
|
||
description: '',
|
||
isOpen: false, // 是否打开过属性选择器
|
||
CartCount: 0, // 购物车数量
|
||
animated: false // 购物车动画
|
||
}
|
||
},
|
||
|
||
computed: {
|
||
...mapGetters(['isLogin', 'uid']),
|
||
|
||
exchangeButtonText() {
|
||
if (this.attr.productSelect && this.attr.productSelect.stock <= 0) {
|
||
return '库存不足'
|
||
}
|
||
return '立即兑换'
|
||
}
|
||
},
|
||
|
||
onLoad(options) {
|
||
if (options.id) {
|
||
this.goodsId = parseInt(options.id)
|
||
this.getDetail()
|
||
}
|
||
},
|
||
|
||
onShow() {
|
||
// 从兑换页面返回时刷新数据
|
||
if (this.goodsId) {
|
||
this.getDetail()
|
||
}
|
||
// 获取购物车数量
|
||
this.getCartCount();
|
||
},
|
||
|
||
methods: {
|
||
// 获取商品详情
|
||
getDetail() {
|
||
let that = this;
|
||
uni.showLoading({
|
||
title: '加载中...'
|
||
})
|
||
getProductDetail(that.goodsId, 1).then(res => {
|
||
let productInfo = res.data.productInfo;
|
||
// 字符串数组转数组;
|
||
let arrayImg = productInfo.sliderImage;
|
||
let sliderImage = JSON.parse(arrayImg);
|
||
that.$set(that, 'sliderImage', sliderImage);
|
||
that.$set(that, 'productInfo', productInfo);
|
||
that.$set(that, 'description', productInfo.content);
|
||
that.$set(that.attr, 'productAttr', res.data.productAttr);
|
||
that.$set(that, 'productValue', res.data.productValue);
|
||
that.skuArr = [];
|
||
for (let key in res.data.productValue) {
|
||
let obj = res.data.productValue[key];
|
||
that.skuArr.push(obj)
|
||
}
|
||
|
||
let productAttr = that.attr.productAttr.map(item => {
|
||
return {
|
||
attrName: item.attrName,
|
||
attrValues: item.attrValues.split(','),
|
||
id: item.id,
|
||
isDel: item.isDel,
|
||
productId: item.productId,
|
||
type: item.type
|
||
}
|
||
});
|
||
that.$set(that.attr, 'productAttr', productAttr);
|
||
|
||
that.DefaultSelect();
|
||
uni.hideLoading();
|
||
}).catch(err => {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: err.msg || '加载失败',
|
||
icon: 'none'
|
||
})
|
||
})
|
||
},
|
||
|
||
/**
|
||
* 默认选中属性
|
||
*
|
||
*/
|
||
DefaultSelect: function() {
|
||
let productAttr = this.attr.productAttr;
|
||
let value = [];
|
||
//默认选中每种规格的第一个
|
||
for (let key in this.productValue) {
|
||
if (this.productValue[key].stock > 0) {
|
||
value = this.attr.productAttr.length ? key.split(",") : [];
|
||
break;
|
||
}
|
||
}
|
||
for (let i = 0; i < value.length; i++) {
|
||
this.$set(productAttr[i], "index", value[i]);
|
||
}
|
||
|
||
//sort();排序函数:数字-英文-汉字;
|
||
let productSelect = this.productValue[value.join(",")];
|
||
if (productSelect && productAttr.length) {
|
||
this.$set(this.attr.productSelect, "storeName", this.productInfo.storeName);
|
||
this.$set(this.attr.productSelect, "image", productSelect.image);
|
||
this.$set(this.attr.productSelect, "price", productSelect.price);
|
||
this.$set(this.attr.productSelect, "stock", productSelect.stock);
|
||
this.$set(this.attr.productSelect, "unique", productSelect.id);
|
||
this.$set(this.attr.productSelect, "cart_num", 1);
|
||
this.$set(this.attr.productSelect, "vipPrice", productSelect.vipPrice);
|
||
this.$set(this.attr.productSelect, 'otPrice', productSelect.otPrice);
|
||
this.$set(this, "attrValue", value.join(","));
|
||
this.$set(this, "attrTxt", "已选择");
|
||
} else if (!productSelect && productAttr.length) {
|
||
this.$set(this.attr.productSelect, "storeName", this.productInfo.storeName);
|
||
this.$set(this.attr.productSelect, "image", this.productInfo.image);
|
||
this.$set(this.attr.productSelect, "price", this.productInfo.price);
|
||
this.$set(this.attr.productSelect, "stock", 0);
|
||
this.$set(this.attr.productSelect, "unique", this.productInfo.id);
|
||
this.$set(this.attr.productSelect, "cart_num", 1);
|
||
this.$set(this.attr.productSelect, "vipPrice", this.productInfo.vipPrice);
|
||
this.$set(this.attr.productSelect, 'otPrice', this.productInfo.otPrice);
|
||
this.$set(this, "attrValue", "");
|
||
this.$set(this, "attrTxt", "请选择");
|
||
} else if (!productSelect && !productAttr.length) {
|
||
this.$set(this.attr.productSelect, "storeName", this.productInfo.storeName);
|
||
this.$set(this.attr.productSelect, "image", this.productInfo.image);
|
||
this.$set(this.attr.productSelect, "price", this.productInfo.price);
|
||
this.$set(this.attr.productSelect, "stock", this.productInfo.stock);
|
||
this.$set(this.attr.productSelect, "unique", this.productInfo.id || "");
|
||
this.$set(this.attr.productSelect, "cart_num", 1);
|
||
this.$set(this.attr.productSelect, "vipPrice", this.productInfo.vipPrice);
|
||
this.$set(this.attr.productSelect, 'otPrice', this.productInfo.otPrice);
|
||
this.$set(this, "attrValue", "");
|
||
this.$set(this, "attrTxt", "已选择");
|
||
}
|
||
},
|
||
|
||
// 预览图片
|
||
previewImage(index) {
|
||
uni.previewImage({
|
||
urls: this.sliderImage,
|
||
current: index
|
||
})
|
||
},
|
||
|
||
// 打开属性选择器
|
||
selecAttr() {
|
||
this.$set(this.attr, 'cartAttr', true);
|
||
this.$set(this, 'isOpen', true);
|
||
},
|
||
|
||
// 关闭属性选择器
|
||
onMyEvent() {
|
||
this.$set(this.attr, 'cartAttr', false);
|
||
this.$set(this, 'isOpen', false);
|
||
},
|
||
|
||
// 属性变动赋值
|
||
ChangeAttr(res) {
|
||
let productSelect = this.productValue[res];
|
||
if (productSelect) {
|
||
this.$set(this.attr.productSelect, "image", productSelect.image);
|
||
this.$set(this.attr.productSelect, "price", productSelect.price);
|
||
this.$set(this.attr.productSelect, "stock", productSelect.stock);
|
||
this.$set(this.attr.productSelect, "unique", productSelect.id);
|
||
this.$set(this.attr.productSelect, "cart_num", 1);
|
||
this.$set(this.attr.productSelect, "vipPrice", productSelect.vipPrice);
|
||
this.$set(this.attr.productSelect, 'otPrice', productSelect.otPrice);
|
||
this.$set(this, "attrValue", res);
|
||
this.$set(this, "attrTxt", "已选择");
|
||
} else {
|
||
this.$set(this.attr.productSelect, "image", this.productInfo.image);
|
||
this.$set(this.attr.productSelect, "price", this.productInfo.price);
|
||
this.$set(this.attr.productSelect, "stock", 0);
|
||
this.$set(this.attr.productSelect, "unique", this.productInfo.id);
|
||
this.$set(this.attr.productSelect, "cart_num", 1);
|
||
this.$set(this.attr.productSelect, "vipPrice", this.productInfo.vipPrice);
|
||
this.$set(this.attr.productSelect, 'otPrice', this.productInfo.otPrice);
|
||
this.$set(this, "attrValue", "");
|
||
this.$set(this, "attrTxt", "请选择");
|
||
}
|
||
},
|
||
|
||
// 购物车数量加减
|
||
ChangeCartNum(changeValue) {
|
||
let productSelect = this.productValue[this.attrValue];
|
||
if (productSelect === undefined && !this.attr.productAttr.length)
|
||
productSelect = this.attr.productSelect;
|
||
if (productSelect === undefined) return;
|
||
|
||
let stock = productSelect.stock || 0;
|
||
let num = this.attr.productSelect;
|
||
if (changeValue) {
|
||
num.cart_num++;
|
||
if (num.cart_num > stock) {
|
||
this.$set(this.attr.productSelect, "cart_num", stock);
|
||
}
|
||
} else {
|
||
num.cart_num--;
|
||
if (num.cart_num < 1) {
|
||
this.$set(this.attr.productSelect, "cart_num", 1);
|
||
}
|
||
}
|
||
},
|
||
|
||
// 属性值选择
|
||
attrVal(val) {
|
||
this.$set(this.attr.productAttr[val.indexw], 'index', this.attr.productAttr[val.indexw].attrValues[val.indexn]);
|
||
},
|
||
|
||
// 购物车手动填写
|
||
iptCartNum(e) {
|
||
this.$set(this.attr.productSelect, 'cart_num', e ? e : 1);
|
||
},
|
||
|
||
// 加入购物车
|
||
onCartAdd() {
|
||
// 检查是否登录
|
||
if (this.isLogin === false) {
|
||
toLogin();
|
||
return;
|
||
}
|
||
|
||
// 调用统一的处理方法,1 表示加入购物车
|
||
this.goCat(1);
|
||
},
|
||
|
||
// 立即兑换
|
||
onExchange() {
|
||
// 检查库存
|
||
if (this.attr.productSelect && this.attr.productSelect.stock <= 0) {
|
||
uni.showToast({
|
||
title: '库存不足',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 检查是否登录
|
||
if (this.isLogin === false) {
|
||
toLogin();
|
||
return;
|
||
}
|
||
|
||
// 调用统一的处理方法,0 表示立即购买
|
||
this.goCat(0);
|
||
},
|
||
|
||
/**
|
||
* 统一处理加入购物车和立即兑换
|
||
* @param {Number} num 1-加入购物车 0-立即购买/兑换
|
||
*/
|
||
goCat(num) {
|
||
let that = this;
|
||
let productSelect = that.productValue[this.attrValue];
|
||
|
||
// 打开属性选择器
|
||
if (that.attrValue) {
|
||
// 默认选中了属性,但是没有打开过属性弹窗还是自动打开让用户查看默认选中的属性
|
||
that.attr.cartAttr = !that.isOpen ? true : false;
|
||
} else {
|
||
if (that.isOpen) that.attr.cartAttr = true;
|
||
else that.attr.cartAttr = !that.attr.cartAttr;
|
||
}
|
||
|
||
// 只有关闭属性弹窗时进行操作
|
||
if (that.attr.cartAttr === true && that.isOpen === false) {
|
||
return (that.isOpen = true);
|
||
}
|
||
|
||
// 如果有属性,没有选择或库存为0,提示用户选择
|
||
if (
|
||
that.attr.productAttr.length &&
|
||
productSelect &&
|
||
productSelect.stock === 0 &&
|
||
that.isOpen === true
|
||
) {
|
||
uni.showToast({
|
||
title: "产品库存不足,请选择其它",
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 执行对应操作
|
||
if (num === 1) {
|
||
// 加入购物车
|
||
let q = {
|
||
productId: parseFloat(that.goodsId),
|
||
cartNum: parseFloat(that.attr.productSelect.cart_num),
|
||
isNew: false,
|
||
productAttrUnique: that.attr.productSelect !== undefined ?
|
||
that.attr.productSelect.unique : that.productInfo.id
|
||
};
|
||
|
||
postCartAdd(q).then(function(res) {
|
||
that.isOpen = false;
|
||
that.attr.cartAttr = false;
|
||
uni.showToast({
|
||
title: "添加购物车成功",
|
||
icon: 'success'
|
||
});
|
||
// 更新购物车数量
|
||
that.getCartCount(true);
|
||
}).catch(res => {
|
||
that.isOpen = false;
|
||
that.attr.cartAttr = false;
|
||
uni.showToast({
|
||
title: res.msg || '添加失败',
|
||
icon: 'none'
|
||
});
|
||
});
|
||
} else {
|
||
// 立即兑换 - 直接跳转到积分商城下单页面
|
||
this.goToConfirm();
|
||
}
|
||
},
|
||
|
||
// 直接跳转到积分商城下单页面
|
||
goToConfirm() {
|
||
// 保存商品信息到缓存
|
||
const goodsInfo = {
|
||
id: this.goodsId,
|
||
name: this.productInfo.storeName,
|
||
storeName: this.productInfo.storeName,
|
||
image: this.attr.productSelect.image || this.productInfo.image,
|
||
pic: this.attr.productSelect.image || this.productInfo.image,
|
||
points: this.attr.productSelect.price || this.productInfo.price,
|
||
integral: this.attr.productSelect.price || this.productInfo.price,
|
||
quantity: this.attr.productSelect.cart_num || 1,
|
||
attrValueId: this.attr.productSelect.unique || '',
|
||
unique: this.attr.productSelect.unique || '',
|
||
productAttrUnique: this.attr.productSelect.unique || '',
|
||
sku: this.attrValue || ''
|
||
};
|
||
|
||
uni.setStorageSync('buy_now_goods', goodsInfo);
|
||
|
||
this.isOpen = false;
|
||
this.attr.cartAttr = false;
|
||
|
||
// 跳转到积分商城下单页面
|
||
uni.navigateTo({
|
||
url: `/pages/integral/confirm?id=${this.goodsId}&quantity=${this.attr.productSelect.cart_num || 1}`
|
||
});
|
||
},
|
||
|
||
/**
|
||
* 获取购物车数量
|
||
* @param {Boolean} isAnima 是否展示购物车动画和重置属性
|
||
*/
|
||
getCartCount(isAnima) {
|
||
let that = this;
|
||
const isLogin = that.isLogin;
|
||
if (isLogin) {
|
||
getCartCounts(true, 'total').then(res => {
|
||
that.CartCount = res.data.count;
|
||
// 加入购物车后重置属性
|
||
if (isAnima) {
|
||
that.animated = true;
|
||
setTimeout(function() {
|
||
that.animated = false;
|
||
}, 500);
|
||
}
|
||
});
|
||
}
|
||
},
|
||
|
||
// 跳转购物车
|
||
goToCart() {
|
||
uni.navigateTo({
|
||
url: '/pages/integral/cart',
|
||
fail: (err) => {
|
||
console.error('跳转购物车失败:', err);
|
||
uni.showToast({
|
||
title: '跳转失败',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
});
|
||
},
|
||
|
||
// 返回上一页
|
||
goBack() {
|
||
uni.navigateBack()
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.goods-detail {
|
||
min-height: 100vh;
|
||
background-color: #F5F5F5;
|
||
padding-bottom: 120rpx;
|
||
}
|
||
|
||
// 顶部导航栏
|
||
.nav-bar {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 113.344rpx;
|
||
background: linear-gradient(180deg, rgba(0, 0, 0, 0.4) 0%, rgba(0, 0, 0, 0) 100%);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 31.996rpx;
|
||
z-index: 200;
|
||
padding-top: constant(safe-area-inset-top);
|
||
padding-top: env(safe-area-inset-top);
|
||
}
|
||
|
||
.nav-back {
|
||
width: 72rpx;
|
||
height: 64rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: rgba(0, 0, 0, 0.3);
|
||
border-radius: 50%;
|
||
|
||
.iconfont {
|
||
font-size: 36rpx;
|
||
color: #FFFFFF;
|
||
}
|
||
}
|
||
|
||
.nav-title {
|
||
flex: 1;
|
||
font-size: 32rpx;
|
||
color: #FFFFFF;
|
||
font-weight: normal;
|
||
text-align: center;
|
||
line-height: 48rpx;
|
||
}
|
||
|
||
.nav-right {
|
||
width: 72rpx;
|
||
height: 64rpx;
|
||
}
|
||
|
||
// 图片轮播
|
||
.goods-swiper {
|
||
width: 100%;
|
||
height: 750rpx;
|
||
background-color: #FFFFFF;
|
||
}
|
||
|
||
.swiper-image {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
// 仿照 goods_details 的 wrapper 样式
|
||
.wrapper {
|
||
background-color: #fff;
|
||
margin: 20rpx;
|
||
padding: 30rpx;
|
||
border-radius: 14rpx;
|
||
}
|
||
|
||
.share-section {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: flex-end;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.money-box {
|
||
display: flex;
|
||
align-items: baseline;
|
||
color: #FF4D4F;
|
||
}
|
||
|
||
.points-num {
|
||
font-size: 48rpx;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.points-symbol {
|
||
font-size: 24rpx;
|
||
margin-right: 4rpx;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.introduce {
|
||
font-size: 32rpx;
|
||
color: #282828;
|
||
font-weight: bold;
|
||
line-height: 1.5;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.label {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
|
||
// 仿照 goods_details 的 attribute 样式
|
||
.attribute {
|
||
background-color: #fff;
|
||
margin: 20rpx;
|
||
padding: 30rpx;
|
||
border-radius: 14rpx;
|
||
}
|
||
|
||
.attr-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.attr-text {
|
||
font-size: 28rpx;
|
||
color: #282828;
|
||
width: 600rpx;
|
||
overflow: hidden;
|
||
white-space: nowrap;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.selected-attr {
|
||
color: #666;
|
||
margin-left: 10rpx;
|
||
}
|
||
|
||
.arrow-right {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
|
||
// 兑换规则
|
||
.rules-section,
|
||
.detail-section {
|
||
margin: 20rpx;
|
||
padding: 30rpx;
|
||
background-color: #FFFFFF;
|
||
border-radius: 20rpx;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 30rpx;
|
||
font-weight: bold;
|
||
color: #333333;
|
||
margin-bottom: 24rpx;
|
||
}
|
||
|
||
.detail-info-list {
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
.detail-item {
|
||
font-size: 26rpx;
|
||
color: #666666;
|
||
margin-bottom: 16rpx;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
// 底部操作栏
|
||
.bottom-bar {
|
||
position: fixed;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: #FFFFFF;
|
||
border-top: 1px solid #EEEEEE;
|
||
padding: 20rpx 30rpx;
|
||
z-index: 100;
|
||
padding-bottom: calc(20rpx + constant(safe-area-inset-bottom));
|
||
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 20rpx;
|
||
}
|
||
|
||
// 浮动购物车按钮
|
||
.floating-cart {
|
||
position: fixed;
|
||
right: 30rpx;
|
||
bottom: calc(240rpx + constant(safe-area-inset-bottom));
|
||
bottom: calc(240rpx + env(safe-area-inset-bottom));
|
||
width: 100rpx;
|
||
height: 100rpx;
|
||
background: #FFFFFF;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.15);
|
||
z-index: 101;
|
||
|
||
.iconfont {
|
||
font-size: 44rpx;
|
||
color: #FF4D4F;
|
||
position: relative;
|
||
}
|
||
|
||
.cart-badge {
|
||
position: absolute;
|
||
top: -8rpx;
|
||
right: -16rpx;
|
||
background: linear-gradient(90deg, #FF6900 0%, #FF4D4F 100%);
|
||
color: #FFFFFF;
|
||
font-size: 18rpx;
|
||
padding: 2rpx 8rpx 3rpx;
|
||
border-radius: 200rpx;
|
||
min-width: 28rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.cart-text {
|
||
font-size: 18rpx;
|
||
color: #666666;
|
||
margin-top: 2rpx;
|
||
}
|
||
}
|
||
|
||
.animated {
|
||
animation-duration: 0.5s;
|
||
animation-fill-mode: both;
|
||
}
|
||
|
||
.bounceIn {
|
||
animation-name: bounceIn;
|
||
}
|
||
|
||
@keyframes bounceIn {
|
||
from,
|
||
20%,
|
||
40%,
|
||
60%,
|
||
80%,
|
||
to {
|
||
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||
}
|
||
|
||
0% {
|
||
opacity: 0;
|
||
transform: scale3d(0.3, 0.3, 0.3);
|
||
}
|
||
|
||
20% {
|
||
transform: scale3d(1.1, 1.1, 1.1);
|
||
}
|
||
|
||
40% {
|
||
transform: scale3d(0.9, 0.9, 0.9);
|
||
}
|
||
|
||
60% {
|
||
opacity: 1;
|
||
transform: scale3d(1.03, 1.03, 1.03);
|
||
}
|
||
|
||
80% {
|
||
transform: scale3d(0.97, 0.97, 0.97);
|
||
}
|
||
|
||
to {
|
||
opacity: 1;
|
||
transform: scale3d(1, 1, 1);
|
||
}
|
||
}
|
||
|
||
.btn-group {
|
||
flex: 1;
|
||
display: flex;
|
||
gap: 20rpx;
|
||
}
|
||
|
||
.btn-cart,
|
||
.btn-buy {
|
||
flex: 1;
|
||
height: 80rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 8rpx;
|
||
font-size: 28rpx;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.btn-cart {
|
||
background-color: #FFFFFF;
|
||
border: 1px solid #EEEEEE;
|
||
color: #333333;
|
||
}
|
||
|
||
.btn-buy {
|
||
background: linear-gradient(90deg, #FF6900 0%, #FF4D4F 100%);
|
||
color: #FFFFFF;
|
||
|
||
&.disabled {
|
||
background: #CCCCCC;
|
||
color: #FFFFFF;
|
||
}
|
||
}
|
||
.detail-content img, .detail-content image{
|
||
width: 100%;
|
||
}
|
||
</style>
|