fix: 更新 API 请求参数格式及优化组件样式

- 将 addEvaluation API 的参数从 params 修改为 data,以符合标准请求格式
- 在多个组件中调整样式,提升响应式布局和用户体验
- 优化商品详情页的倒计时显示,增强视觉效果
- 更新购物车操作按钮样式,提升一致性和可用性
This commit is contained in:
田香琪
2026-06-23 14:13:25 +08:00
parent 8a60e23214
commit 1b2e980fb6
26 changed files with 481 additions and 401 deletions

View File

@@ -158,7 +158,7 @@ export function addEvaluation (params) {
url: `/buyer/member/evaluation`,
method: Method.POST,
needToken: true,
params
data: params
});
}

View File

@@ -18,5 +18,8 @@
}
// 与 CateNav 商品分类栏、Carousel 左占位一致的列宽
$index-main-width: 1200px;
$index-side-col-width: 263.2px;
$index-col-gap: 10px;
// 1200 - 263.2*2 - 10*2 = 653.6px
$index-center-col-width: $index-main-width - ($index-side-col-width * 2) - ($index-col-gap * 2);

View File

@@ -3,7 +3,12 @@
<div class="wrapper" v-if="type === 'goodsDetail'">
<div class="wr-l"><el-icon :size="23"><AlarmClock /></el-icon> 秒杀活动</div>
<div class="count-down" v-if="end === ''">
<p>倒计时</p><span>{{ hours }}</span><span>{{ minutes }}</span><span>{{ seconds }}</span>
<span class="count-down-label">倒计时</span>
<span class="count-down-num">{{ hours }}</span>
<span class="count-down-colon">:</span>
<span class="count-down-num">{{ minutes }}</span>
<span class="count-down-colon">:</span>
<span class="count-down-num">{{ seconds }}</span>
</div>
<div v-else>{{end}}</div>
</div>
@@ -89,36 +94,35 @@ export default {
font-size: 13px;
}
.count-down {
margin-right: -20px;
p{
float: left;
line-height: 20px;
display: flex;
align-items: center;
gap: 4px;
font-size: 13px;
line-height: 1;
.count-down-label {
flex-shrink: 0;
white-space: nowrap;
}
> span {
position: relative;
float: left;
width: 20px;
.count-down-num {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 20px;
height: 20px;
text-align: center;
padding: 0 2px;
background-color: #2f3430;
margin-right: 20px;
color: white;
color: #fff;
font-size: 14px;
line-height: 20px;
&::after {
content: ":";
display: block;
position: absolute;
right: -20px;
font-weight: bolder;
font-size: 14px;
width: 20px;
height: 100%;
top: 0;
}
line-height: 1;
border-radius: 2px;
}
> span:last-child::after {
content: "";
.count-down-colon {
font-weight: bold;
font-size: 14px;
line-height: 1;
}
}

View File

@@ -69,7 +69,12 @@
<p class="remarks-content">{{ item.reply }}</p>
<div>
<div class="comment-img" v-if="item.replyImage">
<div v-for="(img, imgIndex) in item.replyImage.split(',')" @click="$previewImage(img)" :key="imgIndex">
<div
v-for="(img, imgIndex) in item.replyImage.split(',')"
:key="imgIndex"
:class="{ borderColor: img === item.previewImg }"
@click="previewImg(img, item)"
>
<img :src="img" alt="">
</div>
</div>

View File

@@ -226,7 +226,7 @@ export default {
height: 100%;
}
.nav ul {
.nav > ul {
list-style: none;
margin: 0;
padding: 0;
@@ -234,10 +234,11 @@ export default {
align-items: center;
}
.nav li {
.nav > ul > li,
.location > ul.flex > li {
cursor: pointer;
float: none;
line-height: 1;
line-height: 36px;
margin-right: 15px;
display: flex;
align-items: center;
@@ -331,6 +332,7 @@ export default {
.username-p {
position: relative;
z-index: 100;
div {
cursor: pointer;
@@ -345,59 +347,71 @@ export default {
.drop-items {
position: absolute;
display: none;
top: 45px;
left: 0;
right: 0;
margin: 0 auto;
padding: 5px 10px;
z-index: 20;
height: 150px;
flex-direction: column;
top: calc(100% + 10px);
left: 50%;
transform: translateX(-50%);
margin: 0;
padding: 4px 0;
z-index: 1000;
min-width: 100px;
width: max-content;
background-color: #fff;
width: 80px;
border: 1px solid #eee;
box-shadow: 2px 2px 7px #999;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
list-style: none;
li {
color: rgb(107, 106, 106);
display: block;
float: none;
width: 100%;
border-bottom: 1px solid rgb(207, 206, 206);
margin: 0;
padding: 8px 16px;
line-height: 1.4;
color: #666;
font-size: 13px;
font-weight: normal;
text-align: center;
white-space: nowrap;
border-bottom: 1px solid #f0f0f0;
box-sizing: border-box;
&:last-child {
border: none;
border-bottom: none;
}
&:hover {
cursor: pointer;
color: $theme_color;
background-color: #fff7f7;
}
}
&::before {
position: absolute;
top: -20px;
left: 30px;
top: -6px;
left: 50%;
transform: translateX(-50%);
content: '';
width: 0;
height: 0;
border: 10px solid #999;
border-color: transparent transparent #fff transparent;
border: 6px solid transparent;
border-bottom-color: #fff;
}
&::after {
content: '';
position: absolute;
width: 80px;
height: 20px;
top: -20px;
width: 100%;
height: 10px;
top: -10px;
left: 0;
}
}
&:hover {
.drop-items {
display: block;
display: flex;
}
}
}

View File

@@ -38,6 +38,7 @@ export default {
<style lang="scss" scoped>
.model-form {
position: relative;
z-index: 0;
width: 100%;
}
.model-content {

View File

@@ -193,8 +193,10 @@ export default {
}
.carousel-wrap {
width: 100%;
max-width: 1200px;
margin: 0 auto;
box-sizing: border-box;
overflow: visible;
overflow: hidden;
}
.bannerAd{
width: 100%;

View File

@@ -4,15 +4,15 @@
<!-- 侧边导航占位 CateNav 分类栏同宽勿与 CateNav .nav-side 混用类名 -->
<div class="carousel-side-spacer"></div>
<div class="nav-content">
<!-- 轮播图数据时不挂载 el-carousel避免 Element Plus 卸载子项时报错 -->
<!-- 轮播图有效图片时不挂载 el-carousel勿对 el-carousel 使用随图片变化的 key否则 Vue3 patch 会报 emitsOptions 错误 -->
<el-carousel
v-if="carouselList.length"
:key="carouselRenderKey"
v-if="displaySlides.length"
height="334px"
:interval="5000"
:loop="displaySlides.length > 1"
>
<el-carousel-item
v-for="(item, index) in carouselList"
v-for="(item, index) in displaySlides"
:key="carouselItemKey(item, index)"
>
<div class="swiper-img">
@@ -96,10 +96,8 @@ export default {
carouselList() {
return this.data?.options?.list || [];
},
carouselRenderKey() {
const moduleKey = this.data?.key || "carousel";
const imgs = this.carouselList.map((item) => item?.img || "").join("|");
return `${moduleKey}-${this.carouselList.length}-${imgs}`;
displaySlides() {
return this.carouselList.filter((item) => item && item.img);
},
},
data() {
@@ -291,12 +289,14 @@ export default {
}
.model-carousel {
width: 1200px;
max-width: 100%;
width: 100%;
max-width: 1200px;
height: 340px;
margin: 0 auto;
overflow: visible;
overflow: hidden;
box-sizing: border-box;
position: relative;
z-index: 0;
}
.hover-pointer {
@@ -358,14 +358,14 @@ export default {
}
/* 导航主体:固定列宽与 CateNav 完全一致(263.2 + 10 + 637 + 10 + 263.2 = 1183.4px */
/* 导航主体263.2 + 10 + 1fr + 10 + 263.2 = 1200px与下方楼层右缘对齐 */
.nav-body {
width: 1200px;
max-width: 100%;
width: 100%;
max-width: 1200px;
height: 340px;
margin: 0 auto;
display: grid;
grid-template-columns: 263.2px 637px 263.2px;
grid-template-columns: 263.2px minmax(0, 1fr) 263.2px;
column-gap: 10px;
align-items: start;
box-sizing: border-box;
@@ -385,9 +385,8 @@ export default {
/*导航内容*/
.nav-content {
grid-column: 2;
width: 637px;
min-width: 637px;
max-width: 637px;
width: 100%;
min-width: 0;
margin-top: 10px;
height: 333.9px;
position: relative;

View File

@@ -260,7 +260,7 @@ export default {
}
.cate-nav {
position: relative;
z-index: 3;
z-index: 5;
width: 100%;
margin: 14px 0 0;
box-sizing: border-box;
@@ -286,6 +286,7 @@ export default {
font-weight: normal;
color: #333333;
letter-spacing: 0px;
box-sizing: border-box;
}
.nav-item {
flex: 1;
@@ -317,7 +318,7 @@ export default {
position: absolute;
left: 0;
top: 46px;
z-index: 10;
z-index: 1000;
}
.nav-side {
@@ -356,11 +357,14 @@ export default {
.nav-side ul {
width: 100%;
list-style: none;
margin: 0;
padding: 0;
}
.nav-side li {
padding: 0 0 16.2px 37.4px;
font-size: 13px;
line-height: 18px;
box-sizing: border-box;
}
.nav-side-item:hover {
cursor: pointer;

View File

@@ -37,7 +37,7 @@
<div class="width_150">单价</div>
<div class="width_100">数量</div>
<div class="width_150">小计</div>
<div class="width_100">操作</div>
<div class="cart-ops-col">操作</div>
</div>
<div v-if="cartList.length === 0" class="cart-empty">
<p>购物车空空如也</p>
@@ -172,22 +172,21 @@
<div class="width_150">
{{ $filters.unitPrice(goods.subTotal, "¥") }}
</div>
<div class="width_100">
<el-button
v-if="!goods.errorMessage"
size="small"
type="primary"
@click="delGoods(goods.goodsSku.id)"
>删除</el-button
>
<el-button
v-if="!goods.errorMessage"
size="small"
type="info"
@click="collectGoods(goods.goodsSku.id)"
style="margin-left: 10px"
>收藏</el-button
>
<div class="cart-ops-col">
<div v-if="!goods.errorMessage" class="cart-ops">
<el-button
size="small"
class="cart-del-btn"
@click="delGoods(goods.goodsSku.id)"
>删除</el-button
>
<el-button
size="small"
class="cart-collect-btn"
@click="collectGoods(goods.goodsSku.id)"
>收藏</el-button
>
</div>
</div>
<div class="error-goods" v-if="goods.errorMessage">
<div style="margin-top: 20px">{{ goods.errorMessage }}</div>
@@ -767,6 +766,48 @@ export default {
display: flex;
align-items: center;
}
.cart-ops-col {
width: 130px;
min-width: 130px;
flex-shrink: 0;
}
.cart-ops {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
flex-wrap: nowrap;
}
.cart-del-btn {
background-color: #ff7d79 !important;
border-color: #ff7d79 !important;
color: #fff !important;
margin: 0 !important;
&:hover,
&:focus {
background-color: #ff6b66 !important;
border-color: #ff6b66 !important;
color: #fff !important;
}
}
.cart-collect-btn {
background-color: #fa6419 !important;
border-color: #fa6419 !important;
color: #fff !important;
margin: 0 !important;
&:hover,
&:focus {
background-color: #e55a15 !important;
border-color: #e55a15 !important;
color: #fff !important;
}
}
</style>
<style>
.el-input-number .el-input__inner {

View File

@@ -28,10 +28,10 @@
<div class="eval-con">
<div>
<span class="color999">商品评价</span>
<el-radio-group style="margin-bottom:5px;color:#999" v-model="orderGoods.grade" type="button" button-style="solid">
<el-radio label="GOOD">好评</el-radio>
<el-radio label="MODERATE">中评</el-radio>
<el-radio label="WORSE">差评</el-radio>
<el-radio-group v-model="orderGoods.grade">
<el-radio-button value="GOOD">好评</el-radio-button>
<el-radio-button value="MODERATE">中评</el-radio-button>
<el-radio-button value="WORSE">差评</el-radio-button>
</el-radio-group>
<el-input type="textarea" maxlength="500" show-word-limit :rows="4" v-model="orderGoods.content" />
</div>
@@ -106,6 +106,12 @@ export default {
if (!this.form.descriptionScore) {
this.$Message.warning('描述评价不能为空')
return false;
}
if (!this.orderGoods.content || !String(this.orderGoods.content).trim()) {
this.$Message.warning('评论内容不能为空')
return false;
}
this.loading = true;
@@ -118,17 +124,20 @@ export default {
serviceScore: this.form.serviceScore,
deliveryScore: this.form.deliveryScore,
grade: goods.grade,
content: goods.content || '',
images: goods.uploadList.toString()
content: goods.content.trim(),
images: goods.uploadList.length ? goods.uploadList.join(',') : ''
}
addEvaluation(params).then(res => {
this.loading = false
if (res.success) {
this.$Message.success('评价成功')
this.$router.push('/home/CommentList')
} else {
this.$Message.error(res.message || '评价失败,请稍后重试')
}
}).catch(() => {
}).catch((err) => {
this.loading = false;
this.$Message.error(err?.message || '评价失败,请稍后重试')
})
},
goGoodsDetail (skuId, goodsId) { // 跳转商品详情

View File

@@ -29,8 +29,13 @@
<el-input type="number" v-model="form.num" style="width:260px" />
</el-form-item>
<el-form-item label="提交原因" prop="reason">
<el-select v-model="form.reason" style="width:260px">
<el-option v-for="item in reasonList" :value="item.id" :key="item.id">{{ item.reason }}</el-option>
<el-select v-model="form.reason" style="width:260px" placeholder="请选择提交原因">
<el-option
v-for="item in reasonList"
:key="item.id"
:label="item.reason"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="问题描述" prop="problemDesc">

View File

@@ -5,7 +5,7 @@
<div class="address-header">
<span>
{{ item.name }}
<el-tag class="ml_10" v-if="item.isDefault" color="red">默认地址</el-tag>
<el-tag class="ml_10 default-address-tag" v-if="item.isDefault">默认地址</el-tag>
<el-tag class="ml_10" v-if="item.alias" color="warning">{{item.alias}}</el-tag>
</span>
<div class="address-action">
@@ -121,6 +121,12 @@ export default {
cursor: pointer;
}
.default-address-tag {
background-color: #fff3f2 !important;
border: 1px solid $theme_color !important;
color: $theme_color !important;
}
#map-container {
width: 500px;
height: 300px;

View File

@@ -11,7 +11,7 @@
:key="index"
@click="goodsDetail(item.id, item.goodsId)"
>
<img :src="item.thumbnail" :alt="item.thumbnail" width="200" height="200" />
<img :src="item.thumbnail" :alt="item.goodsName" />
<p class="ellipsis">{{ item.goodsName }}</p>
<p>{{ $filters.unitPrice(item.price, "¥") }}</p>
<span class="del-icon" @click.stop="clearById(item.goodsId)">
@@ -132,15 +132,27 @@ export default {
}
.track-list {
display: flex;
flex-wrap: wrap;
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12px;
padding: 0 15px;
box-sizing: border-box;
li {
width: 200px;
width: 100%;
min-width: 0;
overflow: hidden;
margin-left: 15px;
margin-bottom: 10px;
border: 1px solid #eee;
position: relative;
box-sizing: border-box;
img {
width: 100%;
aspect-ratio: 1;
object-fit: cover;
display: block;
}
&:hover {
cursor: pointer;
box-shadow: 1px 1px 3px #999;

View File

@@ -23,7 +23,8 @@
</template>
</ul>
<!-- 秒杀商品列表 -->
<div class="goods-list">
<div class="seckill-goods-wrap">
<div class="goods-list">
<empty v-if="goodsList.length === 0" />
<div v-else class="goods-show-info1" v-for="(item, index) in goodsList" :key="index"
@click="goGoodsDetail(item.skuId, item.goodsId)">
@@ -69,6 +70,7 @@
<span>{{ item.storeName }}</span>
</div>
</div>
</div>
</div>
<BaseFooter />
</div>
@@ -199,10 +201,12 @@ export default {
.time-line {
width: 1200px;
max-width: 1200px;
height: 60px;
margin: 0 auto;
background-color: #fff;
display: flex;
box-sizing: border-box;
li {
padding: 0 30px;
@@ -242,15 +246,29 @@ export default {
}
}
.seckill-goods-wrap {
width: 1200px;
max-width: 1200px;
margin: 0 auto;
box-sizing: border-box;
.goods-list {
width: 100%;
margin: 0;
column-gap: 10px;
}
}
.goods-show-info1 {
width: 290px;
width: calc(25% - 8px);
min-width: 0;
padding: 6px;
margin: 10px 0px;
margin-left: 8px;
margin: 10px 0;
position: relative;
border: 1px solid #fff;
cursor: pointer;
background-color: #fff;
box-sizing: border-box;
}
.goods-show-info1:hover {
@@ -261,6 +279,22 @@ export default {
.goods-show-img {
display: flex;
justify-content: center;
img {
width: 100%;
max-width: 200px;
height: auto;
aspect-ratio: 1;
object-fit: cover;
}
}
.goods-show-num1 {
display: flex;
align-items: center;
font-size: 12px;
margin-bottom: 6px;
color: #666;
}
.el-progress-bar__inner {