feat: ✨ 商品详情页, 引入字体图标
This commit is contained in:
parent
3b994068a8
commit
1ef33c2f70
0
src/@/styles/fonts.scss
Normal file
0
src/@/styles/fonts.scss
Normal file
20
src/App.vue
20
src/App.vue
@ -1,13 +1,17 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onLaunch, onShow, onHide } from "@dcloudio/uni-app";
|
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app'
|
||||||
onLaunch(() => {
|
onLaunch(() => {
|
||||||
console.log("App Launch");
|
console.log('App Launch')
|
||||||
});
|
})
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
console.log("App Show");
|
console.log('App Show')
|
||||||
});
|
})
|
||||||
onHide(() => {
|
onHide(() => {
|
||||||
console.log("App Hide");
|
console.log('App Hide')
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
<style></style>
|
<style lang="scss">
|
||||||
|
// 字体图标
|
||||||
|
@import './styles/fonts.scss';
|
||||||
|
@import './styles/base.scss';
|
||||||
|
</style>
|
||||||
|
@ -57,7 +57,7 @@
|
|||||||
{
|
{
|
||||||
"path": "pages/goods/goods",
|
"path": "pages/goods/goods",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "goods"
|
"navigationBarTitleText": "商品详情"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
126
src/pages/goods/components/AddressPanel.vue
Normal file
126
src/pages/goods/components/AddressPanel.vue
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<template>
|
||||||
|
<view class="address-panel">
|
||||||
|
<!-- 关闭按钮 -->
|
||||||
|
<text class="close icon-close" @tap="emits('close')"></text>
|
||||||
|
<!-- 标题 -->
|
||||||
|
<view class="title">配送至</view>
|
||||||
|
<!-- 内容 -->
|
||||||
|
<view class="content">
|
||||||
|
<view class="item">
|
||||||
|
<view class="user">李明 13824686868</view>
|
||||||
|
<view class="address">北京市顺义区后沙峪地区安平北街6号院</view>
|
||||||
|
<text class="icon icon-checked"></text>
|
||||||
|
</view>
|
||||||
|
<view class="item">
|
||||||
|
<view class="user">王东 13824686868</view>
|
||||||
|
<view class="address">北京市顺义区后沙峪地区安平北街6号院</view>
|
||||||
|
<text class="icon icon-ring"></text>
|
||||||
|
</view>
|
||||||
|
<view class="item">
|
||||||
|
<view class="user">张三 13824686868</view>
|
||||||
|
<view class="address">北京市朝阳区孙河安平北街6号院</view>
|
||||||
|
<text class="icon icon-ring"></text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="footer">
|
||||||
|
<view class="button primary"> 新建地址 </view>
|
||||||
|
<view v-if="false" class="button primary">确定</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const emits = defineEmits<{
|
||||||
|
(e: 'close'): void
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.address-panel {
|
||||||
|
padding: 0 30rpx;
|
||||||
|
border-radius: 10rpx 10rpx 0 0;
|
||||||
|
position: relative;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
line-height: 1;
|
||||||
|
padding: 40rpx 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: normal;
|
||||||
|
border-bottom: 1rpx solid #ddd;
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close {
|
||||||
|
position: absolute;
|
||||||
|
right: 24rpx;
|
||||||
|
top: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
min-height: 300rpx;
|
||||||
|
max-height: 540rpx;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 20rpx;
|
||||||
|
.item {
|
||||||
|
padding: 30rpx 50rpx 30rpx 60rpx;
|
||||||
|
background-size: 40rpx;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 0 center;
|
||||||
|
background-image: url(https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/images/locate.png);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
color: #999;
|
||||||
|
font-size: 40rpx;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
.icon-checked {
|
||||||
|
color: #27ba9b;
|
||||||
|
}
|
||||||
|
.icon-ring {
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
.user {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #444;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.address {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 20rpx 0 40rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #444;
|
||||||
|
|
||||||
|
.button {
|
||||||
|
flex: 1;
|
||||||
|
height: 72rpx;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 72rpx;
|
||||||
|
margin: 0 20rpx;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 72rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #27ba9b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondary {
|
||||||
|
background-color: #ffa868;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
95
src/pages/goods/components/ServicePanel.vue
Normal file
95
src/pages/goods/components/ServicePanel.vue
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
<template>
|
||||||
|
<view class="service-panel">
|
||||||
|
<!-- 关闭按钮 -->
|
||||||
|
<text class="close icon-close" @tap="emits('close')"></text>
|
||||||
|
<!-- 标题 -->
|
||||||
|
<view class="title">服务说明</view>
|
||||||
|
<!-- 内容 -->
|
||||||
|
<view class="content">
|
||||||
|
<view class="item">
|
||||||
|
<view class="dt">无忧退货</view>
|
||||||
|
<view class="dd">
|
||||||
|
自收到商品之日起30天内,可在线申请无忧退货服务(食品等特殊商品除外)
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="item">
|
||||||
|
<view class="dt">快速退款</view>
|
||||||
|
<view class="dd">
|
||||||
|
收到退货包裹并确认无误后,将在48小时内办理退款,
|
||||||
|
退款将原路返回,不同银行处理时间不同,预计1-5个工作日到账
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="item">
|
||||||
|
<view class="dt">满88元免邮费</view>
|
||||||
|
<view class="dd">
|
||||||
|
单笔订单金额(不含运费)满88元可免邮费,不满88元, 单笔订单收取10元邮费
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const emits = defineEmits<{
|
||||||
|
(e: 'close'): void
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.service-panel {
|
||||||
|
padding: 0 30rpx;
|
||||||
|
border-radius: 10rpx 10rpx 0 0;
|
||||||
|
position: relative;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
line-height: 1;
|
||||||
|
padding: 40rpx 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: normal;
|
||||||
|
border-bottom: 1rpx solid #ddd;
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close {
|
||||||
|
position: absolute;
|
||||||
|
right: 24rpx;
|
||||||
|
top: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 20rpx 20rpx 100rpx 20rpx;
|
||||||
|
|
||||||
|
.item {
|
||||||
|
margin-top: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dt {
|
||||||
|
margin-bottom: 10rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 500;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
width: 10rpx;
|
||||||
|
height: 10rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #eaeaea;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: -20rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dd {
|
||||||
|
line-height: 1.6;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,7 +1,458 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="goods">goods</view>
|
<scroll-view scroll-y class="viewport">
|
||||||
|
<!-- 基本信息 -->
|
||||||
|
<view class="goods">
|
||||||
|
<!-- 商品主图 -->
|
||||||
|
<view class="preview">
|
||||||
|
<swiper circular class="swiper" @change="handlerChange">
|
||||||
|
<swiper-item v-for="item in goods?.mainPictures" :key="item">
|
||||||
|
<image mode="aspectFill" :src="item" class="image" />
|
||||||
|
</swiper-item>
|
||||||
|
</swiper>
|
||||||
|
<view class="indicator">
|
||||||
|
<text class="current">{{ currentIndex + 1 }}</text>
|
||||||
|
<text class="split">/</text>
|
||||||
|
<text class="total">{{ goods?.mainPictures.length }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 商品简介 -->
|
||||||
|
<view class="meta">
|
||||||
|
<view class="price">
|
||||||
|
<text class="symbol">¥</text>
|
||||||
|
<text class="number">{{ goods?.price }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="name ellipsis"> {{ goods?.name }} </view>
|
||||||
|
<view class="desc"> {{ goods?.desc }} </view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 操作面板 -->
|
||||||
|
<view class="action">
|
||||||
|
<view class="item arrow">
|
||||||
|
<text class="label">选择</text>
|
||||||
|
<text class="text ellipsis"> 请选择商品规格 </text>
|
||||||
|
</view>
|
||||||
|
<view class="item arrow" @tap="showPopup('address')">
|
||||||
|
<text class="label">送至</text>
|
||||||
|
<text class="text ellipsis"> 请选择收货地址 </text>
|
||||||
|
</view>
|
||||||
|
<view class="item arrow" @tap="showPopup('service')">
|
||||||
|
<text class="label">服务</text>
|
||||||
|
<text class="text ellipsis"> 无忧退 快速退款 免费包邮 </text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 商品详情 -->
|
||||||
|
<view class="detail panel">
|
||||||
|
<view class="title">
|
||||||
|
<text>详情</text>
|
||||||
|
</view>
|
||||||
|
<view class="content">
|
||||||
|
<view class="properties">
|
||||||
|
<!-- 属性详情 -->
|
||||||
|
<view class="item" v-for="item in goods?.details.properties" :key="item.name">
|
||||||
|
<text class="label">{{ item.name }}</text>
|
||||||
|
<text class="value">{{ item.value }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- 图片详情 -->
|
||||||
|
<image
|
||||||
|
mode="widthFix"
|
||||||
|
class="image"
|
||||||
|
:src="item"
|
||||||
|
v-for="(item, index) in goods?.details.pictures"
|
||||||
|
:key="item + index"
|
||||||
|
></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 同类推荐 -->
|
||||||
|
<view class="similar panel">
|
||||||
|
<view class="title">
|
||||||
|
<text>同类推荐</text>
|
||||||
|
</view>
|
||||||
|
<view class="content">
|
||||||
|
<navigator
|
||||||
|
v-for="item in goods?.similarProducts"
|
||||||
|
:key="item.id"
|
||||||
|
class="goods"
|
||||||
|
hover-class="none"
|
||||||
|
:url="`/pages/goods/goods?id=${item.id}`"
|
||||||
|
>
|
||||||
|
<image class="image" mode="widthFix" :src="item.picture"></image>
|
||||||
|
<view class="name ellipsis">{{ item.name }}</view>
|
||||||
|
<view class="price">
|
||||||
|
<text class="symbol">¥</text>
|
||||||
|
<text class="number">{{ item.price }}</text>
|
||||||
|
</view>
|
||||||
|
</navigator>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<!-- 用户操作 -->
|
||||||
|
<view class="toolbar" :style="{ paddingBottom: safeAreaInsets?.bottom + 'px' }">
|
||||||
|
<view class="icons">
|
||||||
|
<button class="icons-button"><text class="icon-heart"></text>收藏</button>
|
||||||
|
<button class="icons-button" open-type="contact">
|
||||||
|
<text class="icon-handset"></text>客服
|
||||||
|
</button>
|
||||||
|
<navigator class="icons-button" url="/pages/cart/cart" open-type="switchTab">
|
||||||
|
<text class="icon-cart"></text>购物车
|
||||||
|
</navigator>
|
||||||
|
</view>
|
||||||
|
<view class="buttons">
|
||||||
|
<view class="addcart"> 加入购物车 </view>
|
||||||
|
<view class="buynow"> 立即购买 </view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 弹出层 -->
|
||||||
|
<uni-popup ref="popup" type="bottom" background-color="#fff">
|
||||||
|
<AddressPanel v-if="popupType === 'address'" @close="handlerClose" />
|
||||||
|
<ServicePanel v-if="popupType === 'service'" @close="handlerClose" />
|
||||||
|
</uni-popup>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts"></script>
|
<script setup lang="ts">
|
||||||
|
import { getGoodsAPI } from '@/services/goods'
|
||||||
|
import type { GoodsResult } from '@/types/goods'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import ServicePanel from './components/ServicePanel.vue'
|
||||||
|
import AddressPanel from './components/AddressPanel.vue'
|
||||||
|
|
||||||
<style lang="scss"></style>
|
// 获取屏幕边界到安全区域距离
|
||||||
|
const { safeAreaInsets } = uni.getSystemInfoSync()
|
||||||
|
|
||||||
|
// 获取路由参数
|
||||||
|
const query = defineProps<{
|
||||||
|
id: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// 商品信息
|
||||||
|
const goods = ref<GoodsResult>()
|
||||||
|
|
||||||
|
// 获取商品信息
|
||||||
|
const getGoods = async () => {
|
||||||
|
const res = await getGoodsAPI(query.id)
|
||||||
|
console.log(res.result)
|
||||||
|
goods.value = res.result
|
||||||
|
}
|
||||||
|
|
||||||
|
// 当前滚动图索引
|
||||||
|
const currentIndex = ref(0)
|
||||||
|
|
||||||
|
// 滚动图索引变化
|
||||||
|
const handlerChange: UniHelper.SwiperOnChange = (e) => {
|
||||||
|
currentIndex.value = e.detail.current
|
||||||
|
}
|
||||||
|
|
||||||
|
// 弹出层类型
|
||||||
|
const popupType = ref<'address' | 'service'>()
|
||||||
|
|
||||||
|
// 弹出层
|
||||||
|
const popup = ref<
|
||||||
|
UniHelper.UniPopupInstance & {
|
||||||
|
open: (type?: UniHelper.UniPopupType) => void
|
||||||
|
close: () => void
|
||||||
|
}
|
||||||
|
>()
|
||||||
|
|
||||||
|
// 显示弹出层
|
||||||
|
const showPopup = (type: NonNullable<typeof popupType.value>) => {
|
||||||
|
popupType.value = type
|
||||||
|
popup.value?.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭弹出层
|
||||||
|
const handlerClose = () => {
|
||||||
|
popup.value?.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoad(() => {
|
||||||
|
getGoods()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
page {
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewport {
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 商品信息 */
|
||||||
|
.goods {
|
||||||
|
background-color: #fff;
|
||||||
|
.preview {
|
||||||
|
height: 750rpx;
|
||||||
|
position: relative;
|
||||||
|
.swiper {
|
||||||
|
height: 750rpx;
|
||||||
|
}
|
||||||
|
.image {
|
||||||
|
width: 750rpx;
|
||||||
|
height: 750rpx;
|
||||||
|
}
|
||||||
|
.indicator {
|
||||||
|
height: 40rpx;
|
||||||
|
padding: 0 24rpx;
|
||||||
|
line-height: 40rpx;
|
||||||
|
border-radius: 30rpx;
|
||||||
|
color: #fff;
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
position: absolute;
|
||||||
|
bottom: 30rpx;
|
||||||
|
right: 30rpx;
|
||||||
|
.current {
|
||||||
|
font-size: 26rpx;
|
||||||
|
}
|
||||||
|
.split {
|
||||||
|
font-size: 24rpx;
|
||||||
|
margin: 0 1rpx 0 2rpx;
|
||||||
|
}
|
||||||
|
.total {
|
||||||
|
font-size: 24rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.meta {
|
||||||
|
position: relative;
|
||||||
|
border-bottom: 1rpx solid #eaeaea;
|
||||||
|
.price {
|
||||||
|
height: 130rpx;
|
||||||
|
padding: 25rpx 30rpx 0;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 34rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: #35c8a9;
|
||||||
|
}
|
||||||
|
.number {
|
||||||
|
font-size: 56rpx;
|
||||||
|
}
|
||||||
|
.brand {
|
||||||
|
width: 160rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
position: absolute;
|
||||||
|
top: 26rpx;
|
||||||
|
right: 30rpx;
|
||||||
|
}
|
||||||
|
.name {
|
||||||
|
max-height: 88rpx;
|
||||||
|
line-height: 1.4;
|
||||||
|
margin: 20rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.desc {
|
||||||
|
line-height: 1;
|
||||||
|
padding: 0 20rpx 30rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #cf4444;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.action {
|
||||||
|
padding-left: 20rpx;
|
||||||
|
.item {
|
||||||
|
height: 90rpx;
|
||||||
|
padding-right: 60rpx;
|
||||||
|
border-bottom: 1rpx solid #eaeaea;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #333;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: 0 none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.label {
|
||||||
|
width: 60rpx;
|
||||||
|
color: #898b94;
|
||||||
|
margin: 0 16rpx 0 10rpx;
|
||||||
|
}
|
||||||
|
.text {
|
||||||
|
flex: 1;
|
||||||
|
-webkit-line-clamp: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
margin-top: 20rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
.title {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
height: 90rpx;
|
||||||
|
line-height: 1;
|
||||||
|
padding: 30rpx 60rpx 30rpx 6rpx;
|
||||||
|
position: relative;
|
||||||
|
text {
|
||||||
|
padding-left: 10rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 600;
|
||||||
|
border-left: 4rpx solid #27ba9b;
|
||||||
|
}
|
||||||
|
navigator {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
right: 30rpx;
|
||||||
|
content: '\e6c2';
|
||||||
|
color: #ccc;
|
||||||
|
font-family: 'erabbit' !important;
|
||||||
|
font-size: 32rpx;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 商品详情 */
|
||||||
|
.detail {
|
||||||
|
padding-left: 20rpx;
|
||||||
|
.content {
|
||||||
|
margin-left: -20rpx;
|
||||||
|
.image {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.properties {
|
||||||
|
padding: 0 20rpx;
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
.item {
|
||||||
|
display: flex;
|
||||||
|
line-height: 2;
|
||||||
|
padding: 10rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #333;
|
||||||
|
border-bottom: 1rpx dashed #ccc;
|
||||||
|
}
|
||||||
|
.label {
|
||||||
|
width: 200rpx;
|
||||||
|
}
|
||||||
|
.value {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 同类推荐 */
|
||||||
|
.similar {
|
||||||
|
.content {
|
||||||
|
padding: 0 20rpx 200rpx;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
.goods {
|
||||||
|
width: calc(375rpx - 60rpx - 14rpx);
|
||||||
|
padding: 24rpx 20rpx 20rpx;
|
||||||
|
margin: 20rpx 7rpx;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
.image {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.name {
|
||||||
|
height: 80rpx;
|
||||||
|
margin: 10rpx 0;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #262626;
|
||||||
|
}
|
||||||
|
.price {
|
||||||
|
line-height: 1;
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: #cf4444;
|
||||||
|
}
|
||||||
|
.number {
|
||||||
|
font-size: 26rpx;
|
||||||
|
margin-left: 2rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
navigator {
|
||||||
|
&:nth-child(even) {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 底部工具栏 */
|
||||||
|
.toolbar {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 1;
|
||||||
|
background-color: #fff;
|
||||||
|
height: 100rpx;
|
||||||
|
padding: 0 20rpx var(--window-bottom);
|
||||||
|
border-top: 1rpx solid #eaeaea;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
box-sizing: content-box;
|
||||||
|
.buttons {
|
||||||
|
display: flex;
|
||||||
|
& > view {
|
||||||
|
width: 220rpx;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 72rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 72rpx;
|
||||||
|
}
|
||||||
|
.addcart {
|
||||||
|
background-color: #ffa868;
|
||||||
|
}
|
||||||
|
.buynow,
|
||||||
|
.payment {
|
||||||
|
background-color: #27ba9b;
|
||||||
|
margin-left: 20rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.icons {
|
||||||
|
padding-right: 10rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex: 1;
|
||||||
|
.icons-button {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.4;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: #333;
|
||||||
|
background-color: #fff;
|
||||||
|
&::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
text {
|
||||||
|
display: block;
|
||||||
|
font-size: 34rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
11
src/services/goods.ts
Normal file
11
src/services/goods.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import type { GoodsResult } from '@/types/goods'
|
||||||
|
import { http } from '@/utils/http'
|
||||||
|
|
||||||
|
/** 获取商品详情 */
|
||||||
|
export const getGoodsAPI = (id: string) => {
|
||||||
|
return http<GoodsResult>({
|
||||||
|
url: '/goods',
|
||||||
|
method: 'GET',
|
||||||
|
data: { id },
|
||||||
|
})
|
||||||
|
}
|
32
src/styles/base.scss
Normal file
32
src/styles/base.scss
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
view,
|
||||||
|
navigator,
|
||||||
|
input,
|
||||||
|
scroll-view {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
button::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
swiper,
|
||||||
|
scroll-view {
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 两行省略
|
||||||
|
.ellipsis {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
147
src/styles/fonts.scss
Normal file
147
src/styles/fonts.scss
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'erabbit';
|
||||||
|
src: url('https://at.alicdn.com/t/c/font_4009193_lnbhmo3yos.woff?t=1681201348304') format('woff'),
|
||||||
|
url('https://at.alicdn.com/t/c/font_4009193_lnbhmo3yos.ttf?t=1681201348304') format('truetype'),
|
||||||
|
url('https://at.alicdn.com/t/c/font_4009193_lnbhmo3yos.svg?t=1681201348304#erabbit')
|
||||||
|
format('svg');
|
||||||
|
}
|
||||||
|
|
||||||
|
[class^='icon-'],
|
||||||
|
[class*=' icon-'] {
|
||||||
|
font-family: 'erabbit' !important;
|
||||||
|
font-style: normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-mail:before {
|
||||||
|
content: '\e644';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-weixin:before {
|
||||||
|
content: '\e620';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-phone:before {
|
||||||
|
content: '\e618';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-camera-plus:before {
|
||||||
|
content: '\e636';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-close:before {
|
||||||
|
content: '\e6e1';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-help:before {
|
||||||
|
content: '\e617';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-cart:before {
|
||||||
|
content: '\e6d1';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-settings:before {
|
||||||
|
content: '\e6cf';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-clock:before {
|
||||||
|
content: '\e609';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-delete:before {
|
||||||
|
content: '\e6ce';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-checked:before {
|
||||||
|
content: '\e6cc';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-ring:before {
|
||||||
|
content: '\e6cd';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-locate:before {
|
||||||
|
content: '\e6cb';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-mark:before {
|
||||||
|
content: '\e6ca';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-check:before {
|
||||||
|
content: '\e6c9';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-handset:before {
|
||||||
|
content: '\e6c8';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-gift:before {
|
||||||
|
content: '\e6c7';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-currency:before {
|
||||||
|
content: '\e6c6';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-comment:before {
|
||||||
|
content: '\e6c5';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-caret:before {
|
||||||
|
content: '\e6c3';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-right:before {
|
||||||
|
content: '\e6c2';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-left:before {
|
||||||
|
content: '\e6c1';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-down:before {
|
||||||
|
content: '\e6c0';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-up:before {
|
||||||
|
content: '\e6bf';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-sort:before {
|
||||||
|
content: '\e616';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-clear:before {
|
||||||
|
content: '\e6be';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-user:before {
|
||||||
|
content: '\e6bb';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-scan:before {
|
||||||
|
content: '\e6bc';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-search:before {
|
||||||
|
content: '\e632';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-preview:before {
|
||||||
|
content: '\e61d';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-heart:before {
|
||||||
|
content: '\e647';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-filter:before {
|
||||||
|
content: '\e629';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-home:before {
|
||||||
|
content: '\e8b9';
|
||||||
|
}
|
90
src/types/goods.d.ts
vendored
Normal file
90
src/types/goods.d.ts
vendored
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import type { AddressItem } from './address'
|
||||||
|
import type { GoodsItem } from './global'
|
||||||
|
|
||||||
|
/** 商品信息 */
|
||||||
|
export type GoodsResult = {
|
||||||
|
/** id */
|
||||||
|
id: string
|
||||||
|
/** 商品名称 */
|
||||||
|
name: string
|
||||||
|
/** 商品描述 */
|
||||||
|
desc: string
|
||||||
|
/** 当前价格 */
|
||||||
|
price: number
|
||||||
|
/** 原价 */
|
||||||
|
oldPrice: number
|
||||||
|
/** 商品详情: 包含详情属性 + 详情图片 */
|
||||||
|
details: Details
|
||||||
|
/** 主图图片集合[ 主图图片链接 ] */
|
||||||
|
mainPictures: string[]
|
||||||
|
/** 同类商品[ 商品信息 ] */
|
||||||
|
similarProducts: GoodsItem[]
|
||||||
|
/** sku集合[ sku信息 ] */
|
||||||
|
skus: SkuItem[]
|
||||||
|
/** 可选规格集合备注[ 可选规格信息 ] */
|
||||||
|
specs: SpecItem[]
|
||||||
|
/** 用户地址列表[ 地址信息 ] */
|
||||||
|
userAddresses: AddressItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 商品详情: 包含详情属性 + 详情图片 */
|
||||||
|
export type Details = {
|
||||||
|
/** 商品属性集合[ 属性信息 ] */
|
||||||
|
properties: DetailsPropertyItem[]
|
||||||
|
/** 商品详情图片集合[ 图片链接 ] */
|
||||||
|
pictures: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 属性信息 */
|
||||||
|
export type DetailsPropertyItem = {
|
||||||
|
/** 属性名称 */
|
||||||
|
name: string
|
||||||
|
/** 属性值 */
|
||||||
|
value: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** sku信息 */
|
||||||
|
export type SkuItem = {
|
||||||
|
/** sku id */
|
||||||
|
id: string
|
||||||
|
/** sku 库存 */
|
||||||
|
inventory: number
|
||||||
|
/** sku 原价 */
|
||||||
|
oldPrice: number
|
||||||
|
/** sku 图片 */
|
||||||
|
picture: string
|
||||||
|
/** sku 当前价 */
|
||||||
|
price: number
|
||||||
|
/** sku 编码 */
|
||||||
|
skuCode: string
|
||||||
|
/** 规格集合[ 规格信息 ] */
|
||||||
|
specs: SkuSpecItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 规格信息 */
|
||||||
|
export type SkuSpecItem = {
|
||||||
|
/** 规格名称 */
|
||||||
|
name: string
|
||||||
|
/** 可选值名称 */
|
||||||
|
valueName: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 可选规格信息 */
|
||||||
|
export type SpecItem = {
|
||||||
|
/** 规格名称 */
|
||||||
|
name: string
|
||||||
|
/** 可选值集合[ 可选值信息 ] */
|
||||||
|
values: SpecValueItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 可选值信息 */
|
||||||
|
export type SpecValueItem = {
|
||||||
|
/** 是否可售 */
|
||||||
|
available: boolean
|
||||||
|
/** 可选值备注 */
|
||||||
|
desc: string
|
||||||
|
/** 可选值名称 */
|
||||||
|
name: string
|
||||||
|
/** 可选值图片链接 */
|
||||||
|
picture: string
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user