fix: 增强错误处理与组件逻辑优化

- 在 App.vue 中添加 JSON 解析错误处理,确保站点信息获取的稳定性。
- 更新多个 API 请求,添加 loading 状态管理,提升用户体验。
- 在 Search.vue 中优化热词列表的解析逻辑,增强容错性。
- 改进购物车、地址管理等 API 请求参数,确保一致性与可用性。
- 新增用户中心布局组件,提升用户界面的一致性与可读性。
This commit is contained in:
田香琪
2026-07-03 18:29:41 +08:00
parent 99de0d4722
commit bd9a5f75b0
79 changed files with 2382 additions and 1207 deletions

View File

@@ -229,11 +229,11 @@ export default {
.advert-list {
width: 100%;
margin: 0;
padding: 5px 0;
padding: 10px;
list-style: none;
box-sizing: border-box;
background: $theme_color;
height: 200px;
height: 210px;
display: flex;
gap: 10px;
align-items: center;

View File

@@ -57,12 +57,14 @@
class="hover-pointer"
@click="linkTo(item.url)"
>
<img :src="item.img" alt="" />
<div class="img-wrap">
<img :src="item.img" alt="" />
<div class="jiaobiao" :class="'jiaobiao' + (index + 1)">
{{ index + 1 }}
</div>
</div>
<p>{{ item.name }}</p>
<p>{{ $filters.unitPrice(item.price, "¥") }}</p>
<div class="jiaobiao" :class="'jiaobiao' + (index + 1)">
{{ index + 1 }}
</div>
</div>
</div>
</div>
@@ -220,16 +222,52 @@ export default {
flex-direction: column;
align-items: center;
overflow: hidden;
img {
border-bottom: 1px solid #eee;
border-right: 1px solid #eee;
.img-wrap {
position: relative;
width: 80px;
height: 80px;
flex-shrink: 0;
display: block;
object-fit: cover;
img {
width: 100%;
height: 100%;
display: block;
object-fit: cover;
}
.jiaobiao {
position: absolute;
width: 23px;
height: 23px;
top: 0;
right: 0;
margin: 0;
padding: 0;
max-height: none;
overflow: visible;
display: block;
background: url(../../../assets/images/festival_icon.png) no-repeat;
color: #fff;
text-align: center;
line-height: 23px;
font-size: 12px;
-webkit-line-clamp: unset;
-webkit-box-orient: unset;
}
.jiaobiao1,
.jiaobiao4 {
background-position: -2px -30px;
}
.jiaobiao2,
.jiaobiao5 {
background-position: -31px -30px;
}
.jiaobiao3,
.jiaobiao6 {
background-position: -60px -30px;
}
}
border-bottom: 1px solid #eee;
border-right: 1px solid #eee;
:nth-child(2) {
> p:nth-child(2) {
width: 100%;
height: auto;
max-height: 32px;
@@ -241,34 +279,12 @@ export default {
-webkit-box-orient: vertical;
text-align: center;
}
:nth-child(3) {
> p:nth-child(3) {
color: $theme_color;
margin-top: 2px;
line-height: 1.2;
flex-shrink: 0;
}
.jiaobiao {
position: absolute;
width: 23px;
height: 23px;
top: 6px;
right: 6px;
background: url(../../../assets/images/festival_icon.png);
color: #fff;
text-align: center;
}
.jiaobiao1,
.jiaobiao4 {
background-position: -2px -30px;
}
.jiaobiao2,
.jiaobiao5 {
background-position: -31px -30px;
}
.jiaobiao3,
.jiaobiao6 {
background-position: -60px -30px;
}
}
> div:nth-child(3n) {
border-right: none;

View File

@@ -83,12 +83,17 @@ export default {
width: 595px;
.content-left {
display: flex;
align-items: stretch;
padding-top: 10px;
font-size: 12px;
box-sizing: content-box;
> div:nth-child(1) {
width: 189px;
border-right: 1px solid #eee;
height: 360px;
display: flex;
flex-direction: column;
box-sizing: border-box;
img {
margin: 40px 0 0 15px;
}
@@ -106,15 +111,20 @@ export default {
color: #999;
}
.view-btn {
margin-left: 15px;
margin-top: 10px;
align-self: center;
width: 145px;
margin-top: auto;
margin-bottom: 15px;
color: #fff;
}
}
> div:nth-child(2) {
width: 405px;
height: 360px;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
box-sizing: border-box;
> div {
display: flex;
align-items: center;
@@ -145,7 +155,7 @@ export default {
grid-template-rows: repeat(2, 1fr);
height: 360px;
padding-top: 10px;
box-sizing: border-box;
box-sizing: content-box;
> div {
width: 100%;

View File

@@ -2,14 +2,14 @@
<div class="model" v-if="data">
<div class="for-your">{{ data.options.title }}</div>
<div class="flex card">
<div class="left">
<div class="left hover-pointer" @click="linkTo(data.options.data.image.url)">
<img :src="data.options.data.image.src" alt="" />
</div>
<div class="right flex">
<!-- 商品区 -->
<div class="goods-list">
<div class="for-your-goods-list">
<div
class="goods-item"
class="for-your-goods-item"
:key="index"
v-for="(item, index) in data.options.data.list"
@click="linkTo(item.url)"
@@ -65,14 +65,18 @@ export default {
</script>
<style scoped lang="scss">
.goods-list {
.for-your-goods-list {
display: flex;
flex: 0 0 558px;
width: 558px;
flex-wrap: wrap;
column-gap: 0;
}
.goods-item {
.for-your-goods-item {
flex: 0 0 278px;
width: 278px;
height: 277px;
min-width: 0;
text-align: center;
box-sizing: border-box;
cursor: pointer;
@@ -84,10 +88,8 @@ export default {
border-top: 1.4px solid #e2e2e2;
}
&:hover {
:deep .goods-name {
color: $theme_color;
}
:deep .goods-desc {
.goods-name,
.goods-desc {
color: $theme_color;
}
}
@@ -105,10 +107,12 @@ export default {
color: #333333;
}
.goods-img {
display: block;
width: 190px;
height: 156px;
margin-top: 19px;
margin: 19px auto 0;
border-radius: 10px;
object-fit: contain;
}
.goods-desc {
font-size: 14px;
@@ -137,6 +141,8 @@ export default {
background: #ffffff;
border-radius: 10px;
position: relative;
overflow: hidden;
flex-shrink: 0;
box-shadow: 0px 1px 13px 0px #E5E5E5;
&:hover {
@@ -159,20 +165,27 @@ export default {
}
}
.left {
flex: 0 0 346px;
width: 346px;
height: 554px;
border-radius: 9.8px 0px 0px 9.8px;
overflow: hidden;
> img {
max-width: 100%;
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
}
.right {
flex: 0 0 839px;
width: 839px;
height: 554px;
border-radius: 0px 9.8px 9.8px 0px;
overflow: hidden;
}
.hot-list {
flex: 0 0 279px;
width: 279px;
}
.hot-title {
@@ -201,8 +214,11 @@ export default {
}
> img {
flex-shrink: 0;
display: block;
width: 76.3px;
height: 77.7px;
object-fit: contain;
}
}
.hot-goods {

View File

@@ -49,5 +49,6 @@ export default {
background: #FFFFFF;
box-shadow: 0px 1px 13px 0px #E5E5E5;
position: relative;
overflow: hidden;
}
</style>

View File

@@ -1,20 +1,23 @@
<template>
<div class="flex" v-if="data.options.right.model == 'brand'">
<div class="left-side" @click="linkTo(data.options.right.data.image.url)">
<img :src="data.options.right.data.image.src" alt="">
<div class="mix-panel flex" v-if="data.options.right.model == 'brand'">
<div class="left-side hover-pointer" @click="linkTo(data.options.right.data.image.url)">
<img :src="data.options.right.data.image.src" alt="" />
</div>
<div class="right-side">
<div class="badge-box flex">
<div class="round">
<el-icon><ArrowRight /></el-icon>
</div>
</div>
<div class="flex goods-list">
<div class="goods-item flex" @click="linkTo(item.url)" :key="index" v-for="(item,index) in data.options.right.data.list">
<div
class="goods-item flex hover-pointer"
@click="linkTo(item.url)"
:key="index"
v-for="(item, index) in data.options.right.data.list"
>
<div class="goods-thumbnail">
<img :src="item.img" alt="">
<img :src="item.img" alt="" />
</div>
</div>
</div>
@@ -23,63 +26,60 @@
</template>
<script>
import { ArrowRight } from '@element-plus/icons-vue';
import { ArrowRight } from "@element-plus/icons-vue";
export default {
name: "mix-goods",
data() {
return {}
},
name: "mix-brand",
components: { ArrowRight },
props: {
data: {
type: Object,
default: {}
}
default: () => ({}),
},
},
components: { ArrowRight },
mounted() {
},
methods: {}
}
};
</script>
<style scoped lang="scss">
.right-side{
width: 330px;
.mix-panel {
height: 100%;
align-items: stretch;
overflow: hidden;
}
.goods-detail-title{
font-size: 13px;
font-weight: normal;
line-height: 16px;
text-align: center;
letter-spacing: 0px;
color: #333333;
}
.goods-detail-price{
font-size: 14px;
font-weight: normal;
line-height: 17px;
letter-spacing: 0px;
color: $theme_color;
margin-top: 8px;
margin-bottom:10px;
}
.goods-thumbnail{
margin-left: 7px;
display: flex;
align-items: center;
>img{
width:90px;
height: 90px;
.left-side {
flex-shrink: 0;
width: 254px;
height: 344px;
> img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 9.8px 0 0 9.8px;
}
}
.badge-box{
margin-top: 33px;
justify-content:right;
>.round{
.right-side {
flex: 1;
min-width: 0;
height: 344px;
display: flex;
flex-direction: column;
box-sizing: border-box;
overflow: hidden;
}
.badge-box {
margin-top: 24px;
margin-bottom: 8px;
justify-content: flex-end;
flex-shrink: 0;
> .round {
width: 17.5px;
height: 17.5px;
opacity: 1;
border-radius: 50%;
text-align: center;
line-height: 17.5px;
@@ -87,47 +87,48 @@ export default {
margin-right: 17.5px;
}
}
.goods-list{
width: 330px;
.goods-list {
width: 100%;
box-sizing: border-box;
flex-wrap: wrap;
justify-content:space-between;
padding: 0 16px;
justify-content: space-between;
align-content: flex-start;
padding: 0 16px 12px;
gap: 8px 0;
flex: 1;
min-height: 0;
overflow: hidden;
}
.goods-item{
.goods-item {
display: flex;
align-items: center;
justify-content: center;
width:50%;
height: 85px;
flex: 0 0 calc(50% - 4px);
width: calc(50% - 4px);
height: 82px;
border-radius: 9.8px;
opacity: 1;
transition: .35s;
background: #FFFFFF;
margin-bottom:9px;
box-sizing: border-box;
overflow: hidden;
background: #ffffff;
transition: 0.35s;
cursor: pointer;
}
.left-side {
>img{
width: 254px;
height: 344px;
border-radius: 9.8px 0px 0px 9.8px;
opacity: 1;
.goods-thumbnail {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
> img {
max-width: 80px;
max-height: 76px;
width: auto;
height: auto;
object-fit: contain;
}
}
.badge {
width: 50px;
height: 27px;
line-height:27px;
border-radius: 13.3px 0px 0px 13.3px;
opacity: 1;
background: #F31947;
font-size: 12.6px;
font-weight: normal;
text-align: center;
letter-spacing: 0px;
color: #FFFFFF;
margin-top: 26px;
margin-bottom:17px;
}
</style>

View File

@@ -1,127 +1,149 @@
<template>
<div class="flex" v-if="data.options.left.model == 'goods'">
<div class="left-side" @click="linkTo(data.options.right.data.image.url)">
<img :src="data.options.left.data.image.src" alt="">
<div class="mix-panel flex" v-if="data.options.left.model == 'goods'">
<div class="left-side hover-pointer" @click="linkTo(data.options.left.data.image.url)">
<img :src="data.options.left.data.image.src" alt="" />
</div>
<div class="right-side">
<div class="badge-box flex">
<div class="badge hover-pointer" @click="linkTo(data.options.left.data.badge.url)">
{{ data.options.left.data.badge.label }}
</div>
</div>
<div class="right-side">
<div class="badge-box flex">
<div class="badge" @click="linkTo(data.options.right.data.image.url)">
{{data.options.left.data.badge.label}}
</div>
<div class="flex goods-list">
<div
class="goods-item flex hover-pointer"
@click="linkTo(item.url)"
:key="index"
v-for="(item, index) in data.options.left.data.list"
>
<div class="goods-thumbnail">
<img :src="item.img" alt="" />
</div>
<div class="flex goods-list">
<div class="goods-item flex" @click="linkTo(item.url)" :key="index" v-for="(item,index) in data.options.left.data.list">
<div class="goods-thumbnail">
<img :src="item.img" alt="">
</div>
<div class="goods-detail">
<div class="goods-detail-title">{{item.title}}</div>
<div class="goods-detail-price">{{ $filters.unitPrice(item.price, '¥') }}</div>
</div>
</div>
<div class="goods-detail">
<div class="goods-detail-title">{{ item.title }}</div>
<div class="goods-detail-price">{{ $filters.unitPrice(item.price, '¥') }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "mix-goods",
data() {
return {}
},
props: {
data: {
type: Object,
default: {}
}
default: () => ({}),
},
},
components: {},
mounted() {
},
methods: {}
}
};
</script>
<style scoped lang="scss">
.right-side{
width: 387px;
.mix-panel {
height: 100%;
align-items: stretch;
overflow: hidden;
}
.goods-detail-title{
.left-side {
flex-shrink: 0;
width: 196.7px;
height: 344px;
> img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 10px 0 0 10px;
}
}
.right-side {
flex: 1;
min-width: 0;
height: 344px;
display: flex;
flex-direction: column;
justify-content: center;
box-sizing: border-box;
overflow: hidden;
}
.goods-detail-title {
font-size: 13px;
font-weight: normal;
line-height: 16px;
text-align: center;
letter-spacing: 0px;
color: #333333;
}
.goods-detail-price{
.goods-detail-price {
font-size: 14px;
font-weight: normal;
line-height: 17px;
letter-spacing: 0px;
color: #F31947;
color: #f31947;
margin-top: 8px;
margin-bottom:10px;
}
.goods-thumbnail{
.goods-thumbnail {
margin-left: 7px;
display: flex;
align-items: center;
>img{
width:90px;
flex-shrink: 0;
> img {
width: 90px;
height: 90px;
object-fit: contain;
}
}
.badge-box{
justify-content:right;
.badge-box {
justify-content: flex-end;
flex-shrink: 0;
}
.goods-list{
width: 387px;
.goods-list {
width: 100%;
box-sizing: border-box;
flex-wrap: wrap;
justify-content:space-between;
justify-content: space-between;
padding: 0 16px;
gap: 9px 0;
}
.goods-item{
.goods-item {
cursor: pointer;
display: flex;
align-items: center;
width: 173.6px;
flex: 0 0 calc(50% - 4px);
width: calc(50% - 4px);
height: 119px;
border-radius: 9.8px;
opacity: 1;
transition: .35s;
background: #FFFFFF;
margin-bottom:9px;
&:hover{
box-shadow: 0px 1px 6px 0px #E5E5E5;
}
box-sizing: border-box;
overflow: hidden;
background: #ffffff;
transition: 0.35s;
}
.left-side {
>img{
border-radius: 10px 0px 0px 10px;
display: block;
width: 196.7px;
height: 343.7px;
&:hover {
box-shadow: 0 1px 6px 0 #e5e5e5;
}
}
.badge {
width: 50px;
height: 27px;
line-height:27px;
border-radius: 13.3px 0px 0px 13.3px;
opacity: 1;
background: #F31947;
line-height: 27px;
border-radius: 13.3px 0 0 13.3px;
background: #f31947;
font-size: 12.6px;
font-weight: normal;
text-align: center;
letter-spacing: 0px;
color: #FFFFFF;
color: #ffffff;
margin-top: 26px;
margin-bottom:17px;
margin-bottom: 17px;
}
</style>

View File

@@ -1,7 +1,12 @@
<template>
<div class="line flex flex-a-c flex-j-sb">
<div class="column" v-for="(item,index) in data.options.list" :key="index">
<img :src="item.img" class="three-column-img">
<div
class="column hover-pointer"
v-for="(item, index) in data.options.list"
:key="index"
@click="linkTo(item.url)"
>
<img :src="item.img" class="three-column-img" alt="" />
</div>
</div>
</template>
@@ -25,12 +30,18 @@ export default {
</script>
<style scoped lang="scss">
.column{
.line {
width: 100%;
}
.column {
width: 385px;
height: 165px;
>img{
cursor: pointer;
> img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
}
</style>