feat: 优化商品详情与购物车功能

- 更新 ShowGoods.vue 和 ShowGoodsDetail.vue 中的按钮样式,统一使用 goods-action-btn 类。
- 在 Cart.vue 中实现商品收藏状态的同步与处理,优化收藏功能的用户体验。
- 调整 GoodsDetail.vue 中的店铺收藏按钮样式,提升视觉一致性。
- 在多个评价组件中引入主题色,增强评分组件的视觉效果。
This commit is contained in:
田香琪
2026-07-09 17:58:01 +08:00
parent ecf11ae2d2
commit c355194aba
15 changed files with 222 additions and 52 deletions

View File

@@ -278,7 +278,7 @@
<div class="item-select-column"> <div class="item-select-column">
<div class="add-buy-car"> <div class="add-buy-car">
<el-button <el-button
type="danger" class="goods-action-btn"
v-if="skuDetail.goodsType !== 'VIRTUAL_GOODS'" v-if="skuDetail.goodsType !== 'VIRTUAL_GOODS'"
:loading="loading" :loading="loading"
:disabled="skuDetail.quantity === 0" :disabled="skuDetail.quantity === 0"
@@ -286,7 +286,7 @@
>加入购物车</el-button >加入购物车</el-button
> >
<el-button <el-button
class="confirm-receipt-btn" class="goods-action-btn"
:loading="loading1" :loading="loading1"
:disabled="skuDetail.quantity === 0" :disabled="skuDetail.quantity === 0"
@click="buyNow" @click="buyNow"
@@ -986,6 +986,28 @@ export default {
> *:last-child { > *:last-child {
margin-right: 0; margin-right: 0;
} }
.goods-action-btn {
background-color: #ff475d !important;
border-color: #ff475d !important;
color: #fff !important;
&:hover,
&:focus {
background-color: #e63e52 !important;
border-color: #e63e52 !important;
color: #fff !important;
}
&.is-disabled,
&.is-disabled:hover,
&.is-disabled:focus {
background-color: #ff475d !important;
border-color: #ff475d !important;
color: #fff !important;
opacity: 0.5;
}
}
} }
.goodsConfig { .goodsConfig {
@@ -1003,7 +1025,7 @@ export default {
&.is-collected { &.is-collected {
.collect-icon { .collect-icon {
color: #ffc107; color: $theme_color;
} }
} }
} }

View File

@@ -38,7 +38,13 @@
</div> </div>
<div class="remarks-content-box"> <div class="remarks-content-box">
<p> <p>
<el-rate disabled :value="Number(item.descriptionScore)" allow-half class="remarks-star"></el-rate> <el-rate
disabled
:model-value="Number(item.descriptionScore) || 0"
allow-half
class="remarks-star"
:colors="['var(--theme-color)', 'var(--theme-color)', 'var(--theme-color)']"
></el-rate>
</p> </p>
<p class="remarks-content">{{item.content}}</p> <p class="remarks-content">{{item.content}}</p>
<div class="comment-img" v-if="item.images"> <div class="comment-img" v-if="item.images">
@@ -546,8 +552,12 @@ export default {
background-color: transparent; background-color: transparent;
} }
} }
:deep(.el-rate__icon) { :deep(.remarks-star.el-rate) {
color: $theme_color; --el-rate-fill-color: #{$theme_color};
--el-rate-disabled-fill-color: #{$theme_color};
}
:deep(.remarks-star .el-rate__icon.is-active) {
color: $theme_color !important;
} }
table{ table{
border-color:#efefef; border-color:#efefef;

View File

@@ -186,8 +186,9 @@
<el-button <el-button
size="small" size="small"
class="cart-collect-btn" class="cart-collect-btn"
@click="collectGoods(goods.goodsSku.id)" :class="{ 'is-collected': goods.isCollected }"
>收藏</el-button @click="handleCollect(goods)"
>{{ goods.isCollected ? "已收藏" : "收藏" }}</el-button
> >
</div> </div>
</div> </div>
@@ -288,16 +289,69 @@ export default {
}); });
window.open(routeUrl.href, "_blank"); window.open(routeUrl.href, "_blank");
}, },
// 收藏商品 // 同步购物车商品收藏状态
collectGoods(id) { async syncCartCollectionStatus() {
if (!this.Cookies.getItem("userInfo") || !this.cartList.length) return;
const skuIds = [];
this.cartList.forEach((shop) => {
(shop.skuList || []).forEach((goods) => {
goods.isCollected = false;
if (goods.goodsSku && goods.goodsSku.id) {
skuIds.push(goods.goodsSku.id);
}
});
});
const uniqueSkuIds = [...new Set(skuIds)];
await Promise.all(
uniqueSkuIds.map(async (skuId) => {
try {
const res = await APIMember.isCollection("GOODS", skuId);
if (res.success && res.result) {
this.cartList.forEach((shop) => {
(shop.skuList || []).forEach((goods) => {
if (goods.goodsSku && goods.goodsSku.id === skuId) {
goods.isCollected = true;
}
});
});
}
} catch (e) {
// 单个查询失败不影响其他商品
}
})
);
this.$forceUpdate();
},
// 收藏 / 取消收藏商品
handleCollect(goods) {
const skuId = goods.goodsSku && goods.goodsSku.id;
if (!skuId) return;
if (goods.isCollected) {
Modal.confirm({
title: "取消收藏",
content: "确定取消收藏该商品吗?",
onOk: () => {
return APIMember.cancelCollect("GOODS", skuId).then((res) => {
if (res.success) {
goods.isCollected = false;
Message.success("取消收藏成功");
this.$forceUpdate();
}
});
},
onCancel: () => {},
});
return;
}
Modal.confirm({ Modal.confirm({
title: "收藏", title: "收藏",
content: "商品收藏后可在个人中心我的收藏查看", content: "商品收藏后可在个人中心我的收藏查看",
onOk: () => { onOk: () => {
APIMember.collectGoods("GOODS", id).then((res) => { return APIMember.collectGoods("GOODS", skuId).then((res) => {
if (res.success) { if (res.success) {
goods.isCollected = true;
Message.success("收藏商品成功"); Message.success("收藏商品成功");
this.getCartList(); this.$forceUpdate();
} }
}); });
}, },
@@ -425,6 +479,7 @@ export default {
} }
this.$forceUpdate(); this.$forceUpdate();
this.allChecked = allChecked; this.allChecked = allChecked;
this.syncCartCollectionStatus();
} }
} catch (error) { } catch (error) {
this.loading = false; this.loading = false;
@@ -878,6 +933,18 @@ export default {
border-color: #e55a15 !important; border-color: #e55a15 !important;
color: #fff !important; color: #fff !important;
} }
&.is-collected {
background-color: $theme_color !important;
border-color: $theme_color !important;
&:hover,
&:focus {
background-color: $theme_color !important;
border-color: $theme_color !important;
opacity: 0.9;
}
}
} }
</style> </style>
<style> <style>

View File

@@ -17,8 +17,12 @@
:to="{ path: '/merchant', query: { id: goodsMsg.data.storeId } }" :to="{ path: '/merchant', query: { id: goodsMsg.data.storeId } }"
>{{ goodsMsg.data.storeName }}</router-link> >{{ goodsMsg.data.storeName }}</router-link>
</span> </span>
<span class="store-collect-btn" @click="collect"> <span
<el-icon :color="storeCollected ? '#ffc107' : '#666'"><StarFilled /></el-icon> class="store-collect-btn"
:class="{ 'is-collected': storeCollected }"
@click="collect"
>
<el-icon class="store-collect-icon"><StarFilled /></el-icon>
{{ storeCollected? "已收藏店铺": "收藏店铺" }} {{ storeCollected? "已收藏店铺": "收藏店铺" }}
</span> </span>
<span class="ml_10 contact-service-btn" @click="IMService(goodsMsg.data.storeId,goodsMsg.data.goodsId,goodsMsg.data.id)">联系客服</span> <span class="ml_10 contact-service-btn" @click="IMService(goodsMsg.data.storeId,goodsMsg.data.goodsId,goodsMsg.data.id)">联系客服</span>
@@ -247,6 +251,17 @@ export default {
cursor: pointer; cursor: pointer;
} }
.store-collect-btn {
.store-collect-icon {
color: #666;
vertical-align: middle;
}
&.is-collected .store-collect-icon {
color: $theme_color;
}
}
.store-name-link { .store-name-link {
color: $theme_color; color: $theme_color;
text-decoration: none; text-decoration: none;

View File

@@ -11,9 +11,9 @@
<div class="delivery-rate"> <div class="delivery-rate">
<div class="fontsize_16">物流服务评价</div> <div class="fontsize_16">物流服务评价</div>
<div class="color999 rate-list"> <div class="color999 rate-list">
<span class="rate-item">物流评价<el-rate v-model="form.deliveryScore" /></span> <span class="rate-item">物流评价<el-rate v-model="form.deliveryScore" :colors="rateThemeColors" class="theme-rate" /></span>
<span class="rate-item">服务评价<el-rate v-model="form.serviceScore" /></span> <span class="rate-item">服务评价<el-rate v-model="form.serviceScore" :colors="rateThemeColors" class="theme-rate" /></span>
<span class="rate-item">描述评价<el-rate v-model="form.descriptionScore" /></span> <span class="rate-item">描述评价<el-rate v-model="form.descriptionScore" :colors="rateThemeColors" class="theme-rate" /></span>
</div> </div>
</div> </div>
<!-- 添加订单评价 左侧商品详情 右侧评价框 --> <!-- 添加订单评价 左侧商品详情 右侧评价框 -->
@@ -96,7 +96,9 @@ export default {
action: commonUrl + '/common/common/upload/file', // 上传地址 action: commonUrl + '/common/common/upload/file', // 上传地址
accessToken: {}, // 验证token accessToken: {}, // 验证token
previewImage: '', // 预览图片地址 previewImage: '', // 预览图片地址
loading: false // 提交加载状态 loading: false, // 提交加载状态
// el-rate SVG 通过 colors 写入 fill-color跟随平台主题色
rateThemeColors: ['var(--theme-color)', 'var(--theme-color)', 'var(--theme-color)']
} }
}, },
methods: { methods: {
@@ -208,6 +210,13 @@ export default {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
} }
.rate-list :deep(.theme-rate.el-rate) {
--el-rate-fill-color: #{$theme_color};
--el-rate-disabled-fill-color: #{$theme_color};
}
:deep(.theme-rate .el-rate__icon.is-active) {
color: $theme_color !important;
}
.goods-eval li{ .goods-eval li{
display: flex; display: flex;
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;

View File

@@ -11,9 +11,9 @@
<div class="delivery-rate"> <div class="delivery-rate">
<div class="fontsize_16">物流服务评价</div> <div class="fontsize_16">物流服务评价</div>
<div class="color999 delivery-rate-items"> <div class="color999 delivery-rate-items">
<span>物流评价<el-rate disabled :model-value="Number(orderGoods.deliveryScore) || 0" /></span> <span>物流评价<el-rate disabled :model-value="Number(orderGoods.deliveryScore) || 0" :colors="rateThemeColors" class="theme-rate" /></span>
<span>服务评价<el-rate disabled :model-value="Number(orderGoods.serviceScore) || 0" /></span> <span>服务评价<el-rate disabled :model-value="Number(orderGoods.serviceScore) || 0" :colors="rateThemeColors" class="theme-rate" /></span>
<span>描述评价<el-rate disabled :model-value="Number(orderGoods.descriptionScore) || 0" /></span> <span>描述评价<el-rate disabled :model-value="Number(orderGoods.descriptionScore) || 0" :colors="rateThemeColors" class="theme-rate" /></span>
</div> </div>
</div> </div>
<!-- 添加订单评价 左侧商品详情 右侧评价框 --> <!-- 添加订单评价 左侧商品详情 右侧评价框 -->
@@ -99,6 +99,8 @@ export default {
visible: false, // 图片预览 visible: false, // 图片预览
previewImage: "", // 预览图片链接 previewImage: "", // 预览图片链接
loading: false, // 加载状态 loading: false, // 加载状态
// el-rate SVG 通过 colors 写入 fill-color跟随平台主题色
rateThemeColors: ["var(--theme-color)", "var(--theme-color)", "var(--theme-color)"],
}; };
}, },
methods: { methods: {
@@ -147,13 +149,13 @@ export default {
gap: 16px; gap: 16px;
} }
.delivery-rate-items :deep(.el-rate) { .delivery-rate-items :deep(.theme-rate.el-rate) {
--el-rate-fill-color: #ffb400; --el-rate-fill-color: #{$theme_color};
--el-rate-disabled-fill-color: #ffb400; --el-rate-disabled-fill-color: #{$theme_color};
} }
:deep(.el-rate__icon.is-active) { :deep(.theme-rate .el-rate__icon.is-active) {
color: #ffb400; color: $theme_color !important;
} }
.goods-eval li { .goods-eval li {
display: flex; display: flex;

View File

@@ -102,6 +102,10 @@ export default {
}) })
}, },
save () { // 提交投诉信息 save () { // 提交投诉信息
if (!this.form.content || !String(this.form.content).trim()) {
Message.warning('投诉内容不能为空')
return
}
let params = { let params = {
goodsId: this.orderGoods.goodsId, goodsId: this.orderGoods.goodsId,
complainTopic: this.form.complainTopic, complainTopic: this.form.complainTopic,

View File

@@ -3,12 +3,12 @@
<el-button @click="handleClickUploadImage">上传图片</el-button> <el-button @click="handleClickUploadImage">上传图片</el-button>
<el-dialog v-model="show" width="850px" title="上传图片" append-to-body :z-index="3500"> <el-dialog v-model="show" width="850px" title="上传图片" append-to-body :z-index="3500">
<div class="import-oss" @click="importOSS">从资源库中导入</div> <div class="import-oss" @click="importOSS">从资源库中导入</div>
<div style="display: flex; flex-wrap: wrap"> <div class="upload-images-wrap">
<vuedraggable <vuedraggable
v-model="images" v-model="images"
:animation="200" :animation="200"
:item-key="draggableItemKey" :item-key="draggableItemKey"
style="display: flex; flex-wrap: wrap" class="upload-images-draggable"
> >
<template #item="{ element, index }"> <template #item="{ element, index }">
<div class="upload-list"> <div class="upload-list">
@@ -67,6 +67,7 @@
ref="ossManage" ref="ossManage"
:is-component="true" :is-component="true"
:initialize="showOssManager" :initialize="showOssManager"
:hide-select-footer="true"
@selected="handleOssSelected" @selected="handleOssSelected"
/> />
<template #footer> <template #footer>
@@ -212,27 +213,57 @@ export default {
.wrapper { .wrapper {
margin: 10px 0; margin: 10px 0;
} }
$upload-item-size: 150px;
.upload-images-wrap {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
}
.upload-images-draggable {
display: flex;
flex-wrap: wrap;
}
.upload-list { .upload-list {
width: 150px; width: $upload-item-size;
height: 150px; height: $upload-item-size;
text-align: center; text-align: center;
border: 1px solid transparent; border: 1px solid #dcdfe6;
border-radius: 4px; border-radius: 4px;
display: inline-block; display: inline-block;
background: #fff; background: #fff;
position: relative; position: relative;
margin-right: 4px; margin: 0 4px 4px 0;
vertical-align: bottom; overflow: hidden;
flex-shrink: 0;
} }
.upload-box { .upload-box {
margin: 10px 0; width: $upload-item-size;
height: $upload-item-size;
margin: 0 4px 4px 0;
display: inline-block; display: inline-block;
vertical-align: bottom; flex-shrink: 0;
:deep(.el-upload) {
width: $upload-item-size;
height: $upload-item-size;
display: block;
}
:deep(.el-upload-dragger) {
width: $upload-item-size;
height: $upload-item-size;
min-height: $upload-item-size;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
box-sizing: border-box;
}
} }
.upload-trigger { .upload-trigger {
width: 148px; width: 100%;
height: 148px; height: 100%;
line-height: 148px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;

View File

@@ -63,6 +63,7 @@
ref="ossManage" ref="ossManage"
:is-component="true" :is-component="true"
:initialize="picModalFlag" :initialize="picModalFlag"
:max-select="1"
@callback="handleOssCallback" @callback="handleOssCallback"
/> />
</el-dialog> </el-dialog>

View File

@@ -60,7 +60,7 @@
<span class="op-split">|</span> <span class="op-split">|</span>
<a class="link-text" @click="openCategoryModal(row)">关联分类</a> <a class="link-text" @click="openCategoryModal(row)">关联分类</a>
<span class="op-split">|</span> <span class="op-split">|</span>
<a class="link-text" @click="delBrand(row.id)">删除</a> <a class="link-text" @click="delBrand(row)">删除</a>
</template> </template>
</template> </template>
</el-table-column> </el-table-column>
@@ -289,12 +289,15 @@ export default {
this.$nextTick(() => this.$forceUpdate()); this.$nextTick(() => this.$forceUpdate());
}); });
}, },
async delBrand(id) { delBrand(row) {
const res = await delBrand(id); ElMessageBox.confirm("您确认要删除 " + row.name + " ?", "确认删除", { type: "warning" }).then(() => {
return delBrand(row.id).then((res) => {
if (res.success) { if (res.success) {
ElMessage.success("品牌删除成功!"); ElMessage.success("品牌删除成功!");
this.getDataList(); this.getDataList();
} }
});
}).catch(() => {});
}, },
init() { init() {
this.getDataList(); this.getDataList();

View File

@@ -142,13 +142,13 @@ export default {
:deep(.el-menu-item.is-active) { :deep(.el-menu-item.is-active) {
background-color: #fff !important; background-color: #fff !important;
color: $theme_color !important; color: var(--el-color-primary) !important;
} }
:deep(.el-menu-item.is-active:hover), :deep(.el-menu-item.is-active:hover),
:deep(.el-menu-item.is-active:focus) { :deep(.el-menu-item.is-active:focus) {
background-color: #fff !important; background-color: #fff !important;
color: $theme_color !important; color: var(--el-color-primary) !important;
} }
} }

View File

@@ -272,7 +272,7 @@
@current-change="pageChange" @current-change="pageChange"
/> />
</div> </div>
<div v-if="isComponent && selectImage" class="oss-select-footer"> <div v-if="isComponent && selectImage && !hideSelectFooter" class="oss-select-footer">
<el-button @click="handleSelectCancel">取消</el-button> <el-button @click="handleSelectCancel">取消</el-button>
<el-button type="primary" @click="handleSelectConfirm">确定</el-button> <el-button type="primary" @click="handleSelectConfirm">确定</el-button>
</div> </div>
@@ -410,6 +410,10 @@ export default {
type: Number, type: Number,
default: 0, default: 0,
}, },
hideSelectFooter: {
type: Boolean,
default: false,
},
}, },
data() { data() {
return { return {

View File

@@ -106,13 +106,13 @@ export default {
:deep(.el-menu-item.is-active) { :deep(.el-menu-item.is-active) {
background-color: #fff !important; background-color: #fff !important;
color: $theme_color !important; color: var(--el-color-primary) !important;
} }
:deep(.el-menu-item.is-active:hover), :deep(.el-menu-item.is-active:hover),
:deep(.el-menu-item.is-active:focus) { :deep(.el-menu-item.is-active:focus) {
background-color: #fff !important; background-color: #fff !important;
color: $theme_color !important; color: var(--el-color-primary) !important;
} }
} }

View File

@@ -645,8 +645,8 @@ html.z-modal body {
} }
.hz-edit-img img { .hz-edit-img img {
max-width: 300px; max-width: 240px;
max-height: 200px; max-height: 140px;
margin-bottom: 10px; margin-bottom: 10px;
} }

View File

@@ -54,6 +54,7 @@
<el-dialog <el-dialog
v-model="showModal" v-model="showModal"
title="编辑热区" title="编辑热区"
width="420px"
:close-on-click-modal="false" :close-on-click-modal="false"
append-to-body append-to-body
@close="cancelZone" @close="cancelZone"
@@ -179,6 +180,7 @@ export default {
this.zoneForm.link = this.$filters.formatLinkType(val); this.zoneForm.link = this.$filters.formatLinkType(val);
this.settingZone(val); this.settingZone(val);
this.changeInfo(this.zoneForm); this.changeInfo(this.zoneForm);
this.showModal = false;
}, },
settingZone(val) { settingZone(val) {
this.zoneForm.type = val.___type || val.type; this.zoneForm.type = val.___type || val.type;