Files
lilishop-ui/buyer/src/components/goodsDetail/ShowGoods.vue
2026-11-05 15:20:38 +08:00

1278 lines
31 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="wrapper">
<div class="item-detail-show">
<!-- 详情左侧展示数据、图片,收藏、举报 -->
<div class="item-detail-left">
<!-- 大图、放大镜(视频商品首项为视频) -->
<div class="item-detail-big-img" v-if="mediaList[mediaIndex]">
<el-image
v-show="!isCurrentVideo"
:src="currentImg"
fit="cover"
style="width: 100%; height: 100%"
/>
<div v-show="isCurrentVideo" class="goods-video-wrap">
<div class="goods-video-bg" :style="videoBgStyle"></div>
<div
v-show="hasVideo"
id="goodsVideoPlayer"
class="goods-video-player"
></div>
</div>
</div>
<div class="item-detail-img-row">
<div
class="item-detail-img-small"
:class="{ 'is-active': mediaIndex === index }"
@mouseover="switchMedia(index)"
v-for="(item, index) in mediaList"
:key="index"
>
<video
v-if="item.type === 'video'"
class="video-thumb"
:src="item.url"
muted
preload="metadata"
playsinline
></video>
<img v-else :src="mediaThumb(item)"/>
<span v-if="item.type === 'video'" class="video-badge">
<img :src="playIcon" alt="" />
</span>
</div>
</div>
<div class="goodsConfig mt_10">
<span
class="collect-btn"
:class="{ 'is-collected': isCollected }"
@click="collect"
>
<el-icon class="collect-icon"><StarFilled /></el-icon>
<span class="collect-text">{{ isCollected ? '已收藏' : '收藏' }}</span>
</span>
</div>
</div>
<!-- 右侧商品信息、活动信息、操作展示 -->
<div class="item-detail-right">
<div class="item-detail-title">
<div class="item-detail-title-row">
<span class="item-detail-name">{{ skuDetail.goodsName }}</span>
</div>
</div>
<div class="sell-point">
{{ skuDetail.sellingPoint }}
</div>
<!-- 限时秒杀 -->
<Promotion
v-if="promotionMap['SECKILL']"
:time="promotionMap['SECKILL'].endTime"
></Promotion>
<!-- 商品详细 价格、优惠券、促销 -->
<div class="item-detail-price-row">
<div class="item-price-left">
<!-- 秒杀价格 -->
<div
class="item-price-row"
v-if="skuDetail.promotionPrice && promotionMap['SECKILL']"
>
<p>
<span class="item-price-title" v-if="promotionMap['SECKILL']"
>秒杀价</span>
<span class="item-price">{{ $filters.unitPrice(skuDetail.promotionPrice, "¥") }}</span>
<span class="item-price-old">{{ $filters.unitPrice(skuDetail.price, "¥") }}</span>
</p>
</div>
<!-- 商品原价 -->
<div class="item-price-row" v-else>
<span class="item-price">{{ $filters.unitPrice(skuDetail.price, "¥") }}</span>
</div>
<!-- 优惠券展示 -->
<div class="item-price-coupon-row" v-if="promotionMap['COUPON'].length">
<span class="item-price-title">优惠券</span>
<div class="coupon-tags">
<span
class="item-coupon"
v-for="(item, index) in promotionMap['COUPON'].slice(0, 6)"
:key="index"
@click="handleReceiveCoupon(item.id)"
>
<span v-if="item.couponType == 'PRICE'"
>{{ item.consumeThreshold > 0 ? '满' + item.consumeThreshold + '减' + item.price : '无门槛,立减' + item.price + '元' }}</span>
<span v-if="item.couponType == 'DISCOUNT'"
>满{{ item.consumeThreshold }}打{{
item.couponDiscount
}}折</span>
</span>
<div class="dropdown" v-if="promotionMap['COUPON'].length > 6">
<span class="dropdown-more">展开更多 ▾</span>
<div class="dropdown-content">
<span
class="item-coupon"
v-for="(item, index) in promotionMap['COUPON'].slice(6, promotionMap['COUPON'].length)"
:key="index"
@click="handleReceiveCoupon(item.id)"
>
<span v-if="item.couponType == 'PRICE'"
>{{ item.consumeThreshold > 0 ? '满' + item.consumeThreshold + '减' + item.price : '无门槛,立减' + item.price + '元' }}</span>
<span v-if="item.couponType == 'DISCOUNT'"
>满{{ item.consumeThreshold }}打{{
item.couponDiscount
}}折</span>
</span>
</div>
</div>
</div>
</div>
<!-- 拼团 -->
<div class="item-price-row" v-if="promotionMap['PINTUAN']">
<p>
<span class="item-price-title">拼团</span>
<span class="item-promotion">拼团价</span>
<span class="item-desc-pintuan" v-if="promotionMap['PINTUAN'].price">
{{ $filters.unitPrice(promotionMap["PINTUAN"].price, "¥") }}
</span>
</p>
</div>
<!-- 满减展示 -->
<div class="item-price-row" v-if="promotionMap['FULL_DISCOUNT']">
<p>
<span class="item-price-title">促销</span>
<span class="item-promotion">满减</span>
<span
class="item-desc-pintuan"
v-if="promotionMap['FULL_DISCOUNT'].fullMinus"
>满{{ promotionMap["FULL_DISCOUNT"].fullMoney }}元,立减现金{{
promotionMap["FULL_DISCOUNT"].fullMinus
}}元</span>
<span
class="item-desc-pintuan"
v-if="
promotionMap['FULL_DISCOUNT'].fullRate &&
promotionMap['FULL_DISCOUNT'].fullRateFlag
"
>满{{ promotionMap["FULL_DISCOUNT"].fullMoney }}元,立享{{
promotionMap["FULL_DISCOUNT"].fullRate
}}折</span>
</p>
</div>
</div>
<div class="item-price-right">
<div class="item-remarks-sum">
<p>累计评价</p>
<p>
<span class="item-remarks-num"
>{{ skuDetail.commentNum || 0 }} 条</span>
</p>
</div>
</div>
</div>
<!-- 选择颜色 -->
<div
class="item-select item-spec"
v-for="(sku, index) in formatList"
:key="sku.name"
>
<div class="item-select-title">
<p>{{ sku.name }}</p>
</div>
<div class="item-select-column">
<div
class="item-select-row"
v-for="item in sku.values"
:key="item.value"
>
<div
class="item-select-box"
@click="select(index, item.value)"
:class="{
'item-select-box-active':
item.value === currentSelceted[index],
}"
>
<div class="item-select-intro">
<p>{{ item.value }}</p>
</div>
</div>
</div>
</div>
</div>
<div class="add-buy-car-box">
<div class="item-select item-spec">
<div class="item-select-title">
<p>数量</p>
</div>
<div class="item-select-column">
<div class="item-select-row">
<el-input-number
:min="1"
:max="quantityMax"
:disabled="isOutOfStock"
v-model="count"
:precision="0"
@blur="changeCount"
></el-input-number>
<span class="inventory">(库存:{{ displayStock }})</span>
</div>
</div>
</div>
<div
class="item-select add-buy-car-row"
v-if="$route.query.way === 'POINT' && skuDetail.authFlag === 'PASS'"
>
<div class="item-select-column">
<div class="add-buy-car">
<el-button
class="goods-action-btn is-solid"
:loading="loading"
:disabled="skuDetail.quantity === 0"
@click="pointPay"
>积分购买</el-button
>
</div>
</div>
</div>
<div
class="item-select add-buy-car-row"
v-if="$route.query.way !== 'POINT' && skuDetail.authFlag === 'PASS'"
>
<div class="item-select-column">
<div class="add-buy-car">
<el-button
class="goods-action-btn"
v-if="!isECouponGoods && skuDetail.goodsType !== 'VIRTUAL_GOODS'"
:loading="loading"
:disabled="isOutOfStock"
@click="addShoppingCartBtn"
>加入购物车</el-button
>
<el-button
class="goods-action-btn is-solid"
v-if="promotionMap['PINTUAN']"
:loading="loadingPintuan"
:disabled="isOutOfStock"
@click="pintuanBuy"
>拼团购买</el-button
>
<el-button
class="goods-action-btn is-solid"
:loading="loading1"
:disabled="isOutOfStock"
@click="buyNow"
>立即购买</el-button
>
<el-alert
v-if="isECouponGoods"
class="e-coupon-after-sale-notice"
type="warning"
:closable="false"
show-icon
:title="eCouponAfterSaleHint()"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, watch, onMounted, onBeforeUnmount, nextTick } from "vue";
import { useRoute, useRouter } from "vue-router";
import { Message } from "@/utils/message";
import { StarFilled } from '@element-plus/icons-vue';
import Promotion from "./Promotion.vue";
import DPlayer from "dplayer";
import storage from "@/plugins/storage.js";
import {
collectGoods,
isCollection,
receiveCoupon,
cancelCollect,
} from "@/api/member.js";
import { addCartGoods } from "@/api/cart.js";
import playIcon from "@/assets/iconfont/play.svg";
/** 卡密商品(E_COUPON)判定与库存工具,见 @/constants/goodsType */
import {
isECoupon,
getECouponStock,
getECouponMaxBuyNum,
createEmptyPromotionMap,
resolveECouponCartType,
eCouponAfterSaleHint,
E_COUPON_CART_BUY_NOW,
E_COUPON_CART_PINTUAN,
E_COUPON_CART_POINTS,
} from "@/constants/goodsType";
defineOptions({ name: "ShowGoods" });
const props = defineProps({
// 商品数据
detail: {
type: Object,
default: null,
},
});
const emit = defineEmits(["handleClickSku"]);
const route = useRoute();
const router = useRouter();
const count = ref(1); // 商品数量
const mediaIndex = ref(0); // 展示媒体下标(相册图片/视频)
const currentSelceted = ref([]); // 当前商品sku
const mediaList = ref([]); // 媒体列表:视频项在前,其后为图片字符串
let dp = null; // DPlayer 实例,有视频时进页即创建(静音自动播放)
const skuDetail = ref({
specList: [],
}); // sku详情
const goodsSpecList = ref(props.detail.specs); // 商品spec
const promotionMap = ref(createEmptyPromotionMap());
const formatList = ref([]); // 选择商品品类的数组
const loading = ref(false); // 立即购买loading
const loading1 = ref(false); // 加入购物车loading
const loadingPintuan = ref(false);
const isCollected = ref(false); // 是否收藏
const skuList = ref([]); // formatSku 中赋值(原 data 未声明)
// startCheckout 通过字符串 key 操作对应 loading
const loadings = { loading, loading1, loadingPintuan };
const currentMedia = computed(() => mediaList.value[mediaIndex.value] || null);
const isCurrentVideo = computed(() => currentMedia.value?.type === "video");
const hasVideo = computed(() =>
mediaList.value.some((item) => item.type === "video")
);
// 视频两侧用封面的高斯模糊填充,避免竖视频出现黑边
const videoBgStyle = computed(() => {
const video = mediaList.value.find((item) => item.type === "video");
return video && video.poster
? { backgroundImage: `url("${video.poster}")` }
: {};
});
const currentImg = computed(() => {
const item = currentMedia.value;
if (!item) return "";
return item.type === "video" ? item.poster : item.url || item;
});
/** 卡密商品:禁加购,仅立即购买;库存读 quantity(M-02 起支持促销) */
const isECouponGoods = computed(() => {
return isECoupon(skuDetail.value.goodsType);
});
const displayStock = computed(() => {
if (isECouponGoods.value) {
return getECouponStock(skuDetail.value);
}
return Number(skuDetail.value.quantity) || 0;
});
const quantityMax = computed(() => {
if (isECouponGoods.value) {
return getECouponMaxBuyNum(skuDetail.value);
}
const qty = Number(skuDetail.value.quantity) || 0;
return qty > 0 ? qty : 1;
});
const isOutOfStock = computed(() => {
if (isECouponGoods.value) {
return getECouponStock(skuDetail.value) <= 0;
}
return (Number(skuDetail.value.quantity) || 0) <= 0;
});
watch(
() => props.detail,
(val) => {
skuDetail.value = val.data;
syncCountWithQuantity();
promotion();
swiperGoodsImg();
},
{ deep: true, immediate: true }
);
// 天猫/淘宝风格:进页即在相册首位静音循环播放,用户可通过控制条开声音
function initVideoPlayer() {
const video = mediaList.value[0];
if (!video || video.type !== "video") return;
nextTick(() => {
if (dp) return;
dp = new DPlayer({
container: document.getElementById("goodsVideoPlayer"),
autoplay: true,
loop: true,
muted: true,
video: {
url: video.url,
pic: video.poster,
},
});
});
}
// 悬停切换相册项:离开视频时暂停,回到视频时续播
function switchMedia(index) {
if (index === mediaIndex.value) return;
const leavingVideo = isCurrentVideo.value;
mediaIndex.value = index;
if (leavingVideo && dp) {
dp.pause();
} else if (isCurrentVideo.value && dp) {
dp.play();
}
}
// 缩略图:视频用封面,图片兼容字符串与 { url } 两种形态
function mediaThumb(item) {
return item.type === "video" ? item.poster : item.url || item;
}
function destroyVideo() {
if (dp) {
dp.destroy();
dp = null;
}
}
function syncCountWithQuantity() {
const qty = isECouponGoods.value
? getECouponStock(skuDetail.value)
: Number(skuDetail.value.quantity) || 0;
if (qty <= 0) {
count.value = 1;
return;
}
const max = isECouponGoods.value ? getECouponMaxBuyNum(skuDetail.value) : qty;
if (count.value > max) {
count.value = max;
} else if (count.value < 1) {
count.value = 1;
}
}
function changeCount(val) {}
function select(index, value) {
// 选择规格
currentSelceted.value[index] = value;
let selectedSkuId = goodsSpecList.value.find((i) => {
let matched = true;
let specValues = i.specValues.filter((j) => j.specName !== "images");
for (let n = 0; n < specValues.length; n++) {
if (specValues[n].specValue !== currentSelceted.value[n]) {
matched = false;
return;
}
}
if (matched) {
return i;
}
});
emit("handleClickSku", {
skuId: selectedSkuId.skuId,
goodsId: skuDetail.value.goodsId,
});
}
function addShoppingCartBtn() {
// FR-B-01:E_COUPON 禁止加购物车(后端亦返回 CARD_KEY_E_COUPON_CART_FORBIDDEN)
if (isECouponGoods.value) {
Message.warning("电子卡券请使用立即购买");
return;
}
// 添加购物车
const params = {
num: count.value,
skuId: skuDetail.value.id,
};
loading.value = true;
addCartGoods(params)
.then((res) => {
loading.value = false;
if (res.success) {
router.push({
path: "/shoppingCart",
query: {
skuId: skuDetail.value.id,
goodsId: skuDetail.value.goodsId,
thumbnail: skuDetail.value.thumbnail,
goodsName: skuDetail.value.goodsName,
count: count.value,
},
});
} else {
Message.warning(res.message);
}
})
.catch(() => {
loading.value = false;
});
}
function buyNow() {
startCheckout(E_COUPON_CART_BUY_NOW, "loading1");
}
function pintuanBuy() {
startCheckout(E_COUPON_CART_PINTUAN, "loadingPintuan");
}
function pointPay() {
startCheckout(E_COUPON_CART_POINTS, "loading");
}
function startCheckout(action, loadingKey) {
const params = {
num: count.value,
skuId: skuDetail.value.id,
cartType: "BUY_NOW",
};
if (skuDetail.value.goodsType === "VIRTUAL_GOODS") {
params.cartType = "VIRTUAL";
} else if (isECouponGoods.value) {
params.cartType = resolveECouponCartType({
routeWay: route.query.way,
action,
});
}
loadings[loadingKey].value = true;
addCartGoods(params)
.then((res) => {
loadings[loadingKey].value = false;
if (res.success) {
router.push({
path: "/pay",
query: { way: params.cartType },
});
} else {
Message.warning(res.message);
}
})
.catch(() => {
loadings[loadingKey].value = false;
});
}
async function collect() {
if (!storage.getItem("accessToken") || !storage.getItem("userInfo")) {
router.push({
path: "/login",
query: {
rePath: route.path,
query: JSON.stringify(route.query || {}),
},
});
return;
}
// 收藏商品
if (isCollected.value) {
let cancel = await cancelCollect("GOODS", skuDetail.value.id);
if (cancel.success) {
Message.success("取消收藏成功");
isCollected.value = false;
}
} else {
let collect = await collectGoods("GOODS", skuDetail.value.id);
if (collect.code === 200) {
isCollected.value = true;
Message.success("收藏商品成功,可以前往个人中心我的收藏查看");
}
}
}
// 格式化数据
function formatSku(list) {
let arr = [{}];
list.forEach((item, index) => {
item.specValues.forEach((spec, specIndex) => {
let name = spec.specName;
let values = {
value: spec.specValue,
quantity: item.quantity,
};
if (name === "images") {
return;
}
arr.forEach((arrItem, arrIndex) => {
if (
arrItem.name === name &&
arrItem.values &&
!arrItem.values.find((i) => i.value === values.value)
) {
arrItem.values.push(values);
}
let keys = arr.map((key) => {
return key.name;
});
if (!keys.includes(name)) {
arr.push({
name: name,
values: [values],
});
}
});
});
});
arr.shift();
formatList.value = arr;
let cur = list.filter((i) => i.skuId === route.query.skuId)[0];
if (cur) {
cur.specValues
.filter((i) => i.specName !== "images")
.forEach((value, _index) => {
currentSelceted.value[_index] = value.specValue;
});
}
skuList.value = list;
}
function handleReceiveCoupon(id) {
// 领取优惠券
receiveCoupon(id).then((res) => {
if (res.success) {
Message.success("优惠券领取成功");
} else {
Message.warning(res.message);
}
});
}
function promotion() {
promotionMap.value = createEmptyPromotionMap();
if (!props.detail || !props.detail.promotionMap) return false;
const keysArr = Object.keys(props.detail.promotionMap);
if (keysArr.length === 0) return false;
for (let i = 0; i < keysArr.length; i++) {
const key = keysArr[i].split("-")[0];
if (key === "COUPON") {
if (!Array.isArray(promotionMap.value.COUPON)) {
promotionMap.value.COUPON = [];
}
promotionMap.value.COUPON.push(props.detail.promotionMap[keysArr[i]]);
} else if (Object.prototype.hasOwnProperty.call(promotionMap.value, key)) {
promotionMap.value[key] = props.detail.promotionMap[keysArr[i]];
} else {
promotionMap.value[key] = props.detail.promotionMap[keysArr[i]];
}
}
}
// 相册里会混进规格 JSON,只留图片地址;没有相册时用主图。有视频时视频排在相册第一项
function swiperGoodsImg() {
destroyVideo();
mediaIndex.value = 0;
const source = skuDetail.value.goodsGalleryList || [];
const gallery = Array.from(source).filter((item) => {
if (typeof item !== "string") return false;
return item.indexOf('"url":') === -1 && item.indexOf('"status":') === -1;
});
const images = gallery.length
? gallery
: skuDetail.value.original
? [skuDetail.value.original]
: [];
mediaList.value = [...images];
if (skuDetail.value.goodsVideo) {
mediaList.value.unshift({
type: "video",
url: skuDetail.value.goodsVideo,
poster: images[0] || "",
});
initVideoPlayer();
}
}
onMounted(() => {
// 用户登录才会判断是否收藏(须同时有 token,避免残留 userInfo 触发 401 跳转登录)
if (storage.getItem("accessToken") && storage.getItem("userInfo")) {
isCollection("GOODS", skuDetail.value.id).then((res) => {
if (res.success && res.result) {
isCollected.value = true;
}
}).catch(() => {
// 收藏状态为可选数据,失败时静默
});
}
formatSku(goodsSpecList.value);
// promotion();
document.title = skuDetail.value.goodsName;
});
onBeforeUnmount(() => {
destroyVideo();
});
</script>
<style scoped lang="scss">
/******************商品图片及购买详情开始******************/
.item-detail-see {
width: 175px;
margin-left: 30px;
}
.flex {
display: flex;
}
.inventory {
padding-left: 4px;
}
.wrapper {
@include white_background_color();
}
.item-num {
text-align: center;
width: 100px;
}
.item-price-num {
font-size: 16px;
color: #666;
}
.item-detail-show {
width: 1200px;
margin: 0 auto;
padding: 24px;
display: flex;
flex-direction: row;
background: #fff;
border-radius: 4px;
box-sizing: border-box;
}
.item-detail-left {
width: 500px;
margin-right: 32px;
flex-shrink: 0;
}
.item-detail-big-img {
width: 500px;
height: 500px;
border-radius: 16px;
overflow: hidden;
margin-bottom: 16px;
background: #f5f5f5;
:deep(.el-image),
:deep(.el-image__inner) {
width: 100%;
height: 100%;
}
:deep(.el-image__inner) {
object-fit: cover;
}
}
.goods-video-wrap {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
.goods-video-bg {
position: absolute;
inset: 0;
background-size: cover;
background-position: center;
filter: blur(28px) brightness(0.85);
transform: scale(1.4);
}
.goods-video-player {
position: relative;
z-index: 1;
width: 100%;
height: 100%;
/* 播放器默认黑底改为透明,露出毛玻璃背景 */
:deep(.dplayer),
:deep(.dplayer-video-wrap) {
background: transparent;
}
}
.video-badge {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: inline-flex;
align-items: center;
justify-content: center;
background: transparent;
img {
width: 22px;
height: 22px;
filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.6));
}
}
.video-thumb {
width: 100%;
height: 100%;
object-fit: cover;
pointer-events: none;
}
.item-detail-img-row {
margin-top: 0;
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.item-detail-img-small {
position: relative;
width: 86px;
height: 86px;
border: 2px solid transparent;
border-radius: 6px;
overflow: hidden;
cursor: pointer;
box-sizing: border-box;
background: #f5f5f5;
&.is-active {
border-color: $theme_color;
}
}
.item-detail-img-small img {
height: 100%;
width: 100%;
object-fit: cover;
}
/*商品选购详情*/
.item-detail-right {
flex: 1;
display: flex;
flex-direction: column;
}
.item-detail-title-row {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
padding: 8px 0;
}
.item-detail-name {
color: #171A26;
font-weight: 400;
font-size: 20px;
line-height: 28px;
}
.item-detail-express {
font-size: 14px;
padding: 2px 3px;
border-radius: 3px;
background-color: $theme_color;
color: #fff;
}
/*商品标签*/
.item-detail-tag {
padding: 8px 0;
font-size: 14px;
color: $theme_color;
}
/*价格详情等*/
.item-detail-price-row {
padding: 16px 20px;
display: flex;
flex-direction: row;
justify-content: space-between;
background: #fafafa;
border-radius: 4px;
}
.item-price-left {
display: flex;
flex-direction: column;
}
.item-price-title {
display: inline-block;
width: 56px;
margin-right: 12px;
color: #666;
font-size: 14px;
text-align: left;
}
.item-price-row {
margin: 4px 0;
> div,
> p {
display: flex;
align-items: center;
margin: 0;
}
}
.item-price {
color: $theme_color;
font-size: 28px;
font-weight: 600;
line-height: 1;
}
.item-price-old {
color: gray;
text-decoration: line-through;
font-size: 14px;
margin-left: 5px;
}
.item-price-coupon-row {
display: flex;
align-items: flex-start;
margin: 8px 0px;
.item-price-title {
flex-shrink: 0;
line-height: 22px;
}
}
.coupon-tags {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 6px;
}
.dropdown {
position: relative;
display: inline-flex;
align-items: center;
cursor: pointer;
z-index: 999;
}
.dropdown-more {
font-size: 12px;
color: #999;
line-height: 22px;
white-space: nowrap;
&:hover {
color: $theme_color;
}
}
.dropdown-content {
display: none;
position: absolute;
top: 24px;
left: 0;
background-color: #fff;
min-width: 220px;
max-width: 320px;
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
padding: 12px;
flex-wrap: wrap;
gap: 6px;
}
.dropdown:hover .dropdown-content {
display: flex;
}
.item-coupon {
position: relative;
padding: 2px 10px;
color: $theme_color;
font-size: 12px;
line-height: 18px;
background-color: #fff;
border: 1px solid $theme_color;
border-radius: 3px;
cursor: pointer;
transition: background-color 0.2s, color 0.2s;
white-space: nowrap;
&:hover {
background-color: $theme_color;
color: #fff;
}
}
.item-promotion {
margin-right: 5px;
padding: 3px;
color: $theme_color;
font-size: 14px;
border: 1px solid $theme_color;
}
.item-price-right {
display: flex;
align-content: center;
align-items: center;
}
.item-remarks-sum {
min-width: 72px;
text-align: center;
padding: 0 4px 0 16px;
border-left: 1px solid #eee;
}
.item-remarks-sum p {
color: #999;
font-size: 13px;
line-height: 20px;
text-align: center;
margin: 0;
}
.item-remarks-num {
line-height: 24px;
color: #171A26;
font-size: 16px;
font-weight: 600;
}
.item-select {
display: flex;
flex-direction: row;
align-items: center;
margin-top: 15px;
}
.item-spec {
flex-direction: column;
align-items: flex-start;
width: 100%;
.item-select-title {
width: auto;
margin-right: 0;
margin-bottom: 16px;
}
.item-select-column {
width: 100%;
}
}
.item-select-title {
color: #666;
font-size: 14px;
margin-right: 16px;
width: 56px;
flex-shrink: 0;
display: flex;
align-items: center;
p {
margin: 0;
}
}
.item-select-column {
display: flex;
flex-wrap: wrap;
align-items: center;
flex: 1;
}
.item-select-row {
display: flex;
align-items: center;
margin-bottom: 8px;
}
.item-select-box {
display: flex;
flex-direction: row;
align-items: center;
}
.item-select-box {
min-height: 36px;
padding: 0 16px;
margin-right: 8px;
background: #fff;
border: 1px solid #e5e5e5;
border-radius: 4px;
cursor: pointer;
color: #171A26;
box-sizing: border-box;
}
.item-select-box:hover {
border-color: $theme_color;
color: $theme_color;
}
.item-select-box-active {
border-color: $theme_color;
background: #fff5f4;
color: $theme_color;
}
.item-select-intro p {
margin: 0;
padding: 8px 0;
font-size: 14px;
line-height: 20px;
}
.add-buy-car-box {
width: 100%;
margin-top: 8px;
border-top: 1px solid #f0f0f0;
}
.e-coupon-after-sale-notice {
width: fit-content;
max-width: 420px;
flex: 0 0 auto;
padding: 4px 10px;
:deep(.el-alert__content) {
padding: 0;
}
:deep(.el-alert__title) {
font-size: 14px;
line-height: 1.5;
}
}
.add-buy-car-row {
margin-top: 25px;
&.item-select {
margin-top: 25px;
}
.item-select-column {
flex: none;
width: 100%;
}
}
.add-buy-car {
display: flex;
align-items: center;
flex-wrap: wrap;
margin-top: 0;
padding-left: 0;
margin-left: 0;
> * {
margin: 0 8px 0 0;
}
> *:last-child {
margin-right: 0;
}
.goods-action-btn {
height: 40px;
min-width: 140px;
padding: 0 24px;
border-radius: 4px;
font-size: 16px;
background: #fff !important;
border: 1px solid $theme_color !important;
color: $theme_color !important;
&:hover,
&:focus {
background: #fff5f4 !important;
border-color: $theme_color !important;
color: $theme_color !important;
}
&.is-solid {
background: $theme_color !important;
color: #fff !important;
&:hover,
&:focus {
background: $theme_color !important;
color: #fff !important;
}
}
&.is-disabled,
&.is-disabled:hover,
&.is-disabled:focus {
opacity: 0.5;
}
}
}
.goodsConfig {
display: flex;
justify-content: space-between;
.collect-btn {
display: inline-flex;
align-items: center;
gap: 4px;
padding-right: 10px;
color: #666;
cursor: pointer;
line-height: 1;
&.is-collected {
.collect-icon {
color: $theme_color;
}
}
}
.collect-icon {
display: inline-flex;
align-items: center;
font-size: 16px;
}
.collect-text {
line-height: 1;
}
}
.sell-point {
font-size: 14px;
line-height: 22px;
color: #999;
margin-bottom: 12px;
}
.inventory {
padding-left: 8px;
color: #666;
font-size: 15px;
line-height: 22px;
}
/******************商品图片及购买详情结束******************/
</style>