-
6src/pages.json
-
50src/subpackage/mall/components/bottom_modal.vue
-
2src/subpackage/mall/components/line_button.vue
-
18src/subpackage/mall/components/number_operate.vue
-
144src/subpackage/mall/components/specification_modal.vue
-
6src/subpackage/mall/js/api.js
-
484src/subpackage/mall/pages/goods_info.vue
-
9src/subpackage/mall/pages/index.vue
-
BINsrc/subpackage/mall/static/images/arrow_873.png
-
BINsrc/subpackage/mall/static/images/arrow_9ad.png
-
BINsrc/subpackage/mall/static/images/home.png
-
BINsrc/subpackage/mall/static/images/selected.png
-
BINsrc/subpackage/mall/static/images/share.png
-
BINsrc/subpackage/mall/static/images/shopping_cart.png
-
BINsrc/subpackage/mall/static/images/star.png
-
12src/uni.scss
@ -0,0 +1,50 @@ |
|||||
|
<template> |
||||
|
<view class="bottom-modal"> |
||||
|
<view class="bm-container"> |
||||
|
<view class="bc-title">配送说明</view> |
||||
|
<view class="bc-bot-btn"> |
||||
|
<view class="bbb-item">关闭</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
|
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss"> |
||||
|
.bottom-modal{ |
||||
|
position: fixed; |
||||
|
left: 0; |
||||
|
top: 0; |
||||
|
right: 0; |
||||
|
bottom: 0; |
||||
|
background-color: rgba(0, 0, 0, .5); |
||||
|
.bm-container{ |
||||
|
position: absolute; |
||||
|
left: 0; |
||||
|
bottom: 0; |
||||
|
padding: 50rpx 20upx 10upx; |
||||
|
width: 100%; |
||||
|
background-color: #fff; |
||||
|
@include isPd(10upx); |
||||
|
.bc-title{ |
||||
|
text-align: center; |
||||
|
@include flcw(32upx, 44upx, #333, 500); |
||||
|
@include tHide; |
||||
|
} |
||||
|
.bc-bot-btn{ |
||||
|
padding-top: 18upx; |
||||
|
.bbb-item{ |
||||
|
text-align: center; |
||||
|
background: $mColor; |
||||
|
border-radius: 44upx; |
||||
|
@include flcw(32upx, 88upx, #fff, 500); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
@ -1,8 +1,10 @@ |
|||||
import { ORIGIN } from '@/js/api'; |
|
||||
|
|
||||
|
// import { ORIGIN } from '@/js/api';
|
||||
|
const ORIGIN = `https://test.ouxuanzhineng.cn`; // 测试
|
||||
export const MALL_API = { |
export const MALL_API = { |
||||
homeShow:`${ORIGIN}/shop2/homeShow`, // 首页设置信息
|
homeShow:`${ORIGIN}/shop2/homeShow`, // 首页设置信息
|
||||
goodsCartAdd:`${ORIGIN}/shop2/goodsCartAdd`, //购物车 - 添加商品
|
goodsCartAdd:`${ORIGIN}/shop2/goodsCartAdd`, //购物车 - 添加商品
|
||||
|
goodsSpecSel:`${ORIGIN}/shop2/goodsSpecSel`, //商品规格选择【返回库存&价格】
|
||||
|
goodsInfo:`${ORIGIN}/shop2/goodsInfo`, //商品详情
|
||||
} |
} |
||||
|
|
||||
export default { ORIGIN, MALL_API }; |
export default { ORIGIN, MALL_API }; |
@ -0,0 +1,484 @@ |
|||||
|
<template> |
||||
|
<view class="goods-info"> |
||||
|
<view class="gi-header"> |
||||
|
<!-- banner 图 --> |
||||
|
<view class="gi-box"> |
||||
|
<swiper class="gi-banner" @change="curBannerIdx = $event.detail.current" autoplay> |
||||
|
<swiper-item v-for="(e, i) in goodsInfo.product_imgs" :key="i"> |
||||
|
<image class="gb-img" mode="aspectFill" :src="e"></image> |
||||
|
</swiper-item> |
||||
|
</swiper> |
||||
|
<button class="gb-share"> |
||||
|
<image class="gs-img" mode="aspectFit" src="/subpackage/mall/static/images/share.png"></image> |
||||
|
</button> |
||||
|
<view class="gb-num" v-if="bannerNumStr">{{ bannerNumStr }}</view> |
||||
|
</view> |
||||
|
<!-- 价格 名称 等文案信息 --> |
||||
|
<view class="gi-txt-info"> |
||||
|
<view class="gti-price"> |
||||
|
<view class="gp-sell">¥{{ showPrice || 0 }}</view> |
||||
|
<view class="gp-del" v-if="isShowDelPrice">价格¥{{ goodsInfo.product_spec_single_info.price_show || '0' }}</view> |
||||
|
</view> |
||||
|
<view class="gti-discounts"> |
||||
|
<!-- <view class="gd-left"> |
||||
|
<view class="gl-integration">5000积分</view> |
||||
|
<view class="gl-tag">特价</view> |
||||
|
</view> --> |
||||
|
<view class="gd-right" v-if="false"> |
||||
|
<text class="gr-txt">领券</text> |
||||
|
<image class="gr-img" mode="aspectFit" src="/subpackage/mall/static/images/arrow_873.png"></image> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="gti-bottom"> |
||||
|
<view class="gb-left"> |
||||
|
<view class="gb-name">{{ goodsInfo.product_name || '' }}</view> |
||||
|
<view class="gb-desc">{{ goodsInfo.product_text || '' }}</view> |
||||
|
</view> |
||||
|
<view class="gb-right"> |
||||
|
<view class="gr-num">{{ getCommentLevelTxt }}</view> |
||||
|
<view class="gr-star-ls"> |
||||
|
<block v-for="i in getCommentLevelStartNum" :key="i"> |
||||
|
<image class="gsl-img" mode="aspectFit" src="/subpackage/mall/static/images/star.png"></image> |
||||
|
</block> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
<!-- 配送 说明 已选 --> |
||||
|
<view class="gi-selected"> |
||||
|
<view class="gs-item"> |
||||
|
<view class="gs-name">配送</view> |
||||
|
<view class="gs-content"> |
||||
|
<text class="gc-txt">{{ getDeliveryTxt }}</text> |
||||
|
</view> |
||||
|
<image class="gs-icon" mode="aspectFit" src="/subpackage/mall/static/images/arrow_9ad.png"></image> |
||||
|
</view> |
||||
|
<view class="gs-item"> |
||||
|
<view class="gs-name">说明</view> |
||||
|
<view class="gs-content"> |
||||
|
<block v-for="(e, i) in getExplianKeyTxt" :key="i"> |
||||
|
<image class="gc-icon" mode="aspectFit" src="/subpackage/mall/static/images/selected.png"></image> |
||||
|
<text class="gc-txt">{{ e || '' }}</text> |
||||
|
</block> |
||||
|
</view> |
||||
|
<image class="gs-icon" mode="aspectFit" src="/subpackage/mall/static/images/arrow_9ad.png"></image> |
||||
|
</view> |
||||
|
<view class="gs-item"> |
||||
|
<view class="gs-name">已选</view> |
||||
|
<view class="gs-content"> |
||||
|
<block v-for="i in 3" :key="i"> |
||||
|
<image class="gc-icon"></image> |
||||
|
<text class="gc-txt">配送/自提</text> |
||||
|
</block> |
||||
|
</view> |
||||
|
<image class="gs-icon" mode="aspectFit" src="/subpackage/mall/static/images/arrow_9ad.png"></image> |
||||
|
</view> |
||||
|
</view> |
||||
|
<!-- 商品详情 --> |
||||
|
<view class="gi-detail"> |
||||
|
<view class="gd-title"> |
||||
|
<view class="gt-icon"></view> |
||||
|
<view class="gt-txt">商品详情</view> |
||||
|
<view class="gt-icon"></view> |
||||
|
</view> |
||||
|
<rich-text class="gd-rich-txt" :nodes="getRichTxtForDetail"></rich-text> |
||||
|
</view> |
||||
|
<!-- 底部悬浮按钮 --> |
||||
|
<view class="gd-fixed-bar"> |
||||
|
<view class="gfb-left"> |
||||
|
<view class="gl-box"> |
||||
|
<image class="gb-icon" mode="aspectFit" src="/subpackage/mall/static/images/home.png"></image> |
||||
|
<view class="gb-txt">首页</view> |
||||
|
</view> |
||||
|
<view class="gl-box"> |
||||
|
<image class="gb-icon" mode="aspectFit" src="/subpackage/mall/static/images/shopping_cart.png"></image> |
||||
|
<view class="gb-txt">购物车</view> |
||||
|
<view class="gb-num">99</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="gfb-btns"> |
||||
|
<view class="gb-item">加入购物车</view> |
||||
|
<view class="gb-item">立即购买</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<bottom-modal></bottom-modal> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { routeTo, showLoad, hideLoad, showModal, tsRoute, jsonStr, jsonPar } from "@/utils/util.js"; |
||||
|
import bottomModal from "../components/bottom_modal.vue"; |
||||
|
import { MALL_API } from "../js/api"; |
||||
|
import server from "../js/server"; |
||||
|
export default { |
||||
|
components: { |
||||
|
bottomModal |
||||
|
}, |
||||
|
data(){ |
||||
|
return { |
||||
|
goodsInfo: {}, |
||||
|
curBannerIdx: 0, |
||||
|
} |
||||
|
}, |
||||
|
computed: { |
||||
|
// banner页码 |
||||
|
bannerNumStr(){ |
||||
|
let { goodsInfo, curBannerIdx } = this; |
||||
|
if(goodsInfo?.product_imgs?.length >= 1)return `${curBannerIdx + 1}/${goodsInfo?.product_imgs?.length ?? ''}`; |
||||
|
return ''; |
||||
|
}, |
||||
|
// <!-- product_spec_multi等于0是单规格 才显示划线价格 --> |
||||
|
isShowDelPrice(){ |
||||
|
let { goodsInfo } = this; |
||||
|
return goodsInfo?.product_spec_multi == 0 && goodsInfo?.product_spec_single_info?.price_show > 0 |
||||
|
}, |
||||
|
// 显示价格 |
||||
|
showPrice(){ |
||||
|
let { goodsInfo } = this; |
||||
|
if(goodsInfo?.product_spec_multi == 0)return goodsInfo?.product_spec_single_info?.price ?? 0; |
||||
|
return goodsInfo?.product_price ?? 0; |
||||
|
}, |
||||
|
// 商品详情富文本 |
||||
|
getRichTxtForDetail(){ |
||||
|
let { goodsInfo } = this; |
||||
|
let _html = goodsInfo.product_desc || ''; |
||||
|
return _html.replace(/<img/gi, "<img style='width:100%;height:auto;'"); |
||||
|
}, |
||||
|
// 配送文案 |
||||
|
getDeliveryTxt(){ |
||||
|
/** |
||||
|
* @param {Number} product_logistics 0-仅支持物流 1-仅支持自提 2-支持物流+自提 |
||||
|
* */ |
||||
|
let { goodsInfo } = this; |
||||
|
let _txtArr = ['快递', '自提', '快递/自提']; |
||||
|
let _logisticsNum = goodsInfo?.product_logistics; |
||||
|
if([0,1,2].includes(_logisticsNum))return _txtArr[_logisticsNum]; |
||||
|
return ''; |
||||
|
}, |
||||
|
// 说明列表 |
||||
|
getExplianKeyTxt(){ |
||||
|
let { goodsInfo } = this; |
||||
|
let _txtArr = Object.keys(goodsInfo?.product_service_tags ?? {}); |
||||
|
if(_txtArr.length >= 1)return _txtArr.splice(0, 3); |
||||
|
}, |
||||
|
// 评价等级文案 |
||||
|
getCommentLevelTxt(){ |
||||
|
let { goodsInfo } = this; |
||||
|
let _num = goodsInfo?.product_comment_level ?? 0; |
||||
|
if(_num%1==0) return _num + '.0'; |
||||
|
return _num; |
||||
|
}, |
||||
|
// 评价等级星星数量 |
||||
|
getCommentLevelStartNum(){ |
||||
|
let { goodsInfo } = this; |
||||
|
let _num = +(goodsInfo?.product_comment_level ?? 0); |
||||
|
if(isNaN(_num))return 0; |
||||
|
let _rNum = Math.round(_num) |
||||
|
return _rNum > 5 ? 5 : _rNum; |
||||
|
} |
||||
|
}, |
||||
|
onLoad(options){ |
||||
|
this.getGoodsInfo({ |
||||
|
brand_id: options?.brand_id ?? '', |
||||
|
id: options?.id ?? '' |
||||
|
}) |
||||
|
}, |
||||
|
methods: { |
||||
|
getGoodsInfo({ brand_id, id }){ |
||||
|
showLoad(); |
||||
|
return server.post({ |
||||
|
url: MALL_API.goodsInfo, |
||||
|
data: { brand_id, id }, |
||||
|
isDefaultGet: false, |
||||
|
}) |
||||
|
.then(res => { |
||||
|
hideLoad(); |
||||
|
let _data = res?.data || {}; |
||||
|
if(_data.code === 0){ |
||||
|
console.log('subpackage mall pages goods_info getGoodsInfo res --->', _data); |
||||
|
return this.goodsInfo = _data?.data ?? {}; |
||||
|
}else{ |
||||
|
return Promise.reject(_data); |
||||
|
} |
||||
|
}) |
||||
|
.catch(err => { |
||||
|
hideLoad(); |
||||
|
showModal({ |
||||
|
title: '提示', |
||||
|
content: err.message || '加载失败!' |
||||
|
}) |
||||
|
console.warn('subpackage mall pages goods_info getGoodsInfo err --->', err); |
||||
|
}) |
||||
|
}, |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss"> |
||||
|
.goods-info{ |
||||
|
@include isPd(134upx); |
||||
|
} |
||||
|
.gi-box{ |
||||
|
position: relative; |
||||
|
.gi-banner{ |
||||
|
height: 750rpx; |
||||
|
.gb-img{ |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
} |
||||
|
} |
||||
|
.gb-share{ |
||||
|
@include clearBtn; |
||||
|
position: absolute; |
||||
|
top: 20rpx; |
||||
|
right: 20rpx; |
||||
|
width: 56rpx; |
||||
|
height: 56rpx; |
||||
|
.gs-img{ |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
} |
||||
|
} |
||||
|
.gb-num{ |
||||
|
position: absolute; |
||||
|
bottom: 20rpx; |
||||
|
right: 20rpx; |
||||
|
padding: 0 22rpx; |
||||
|
background: rgba(0, 0, 0, 0.5); |
||||
|
border-radius: 20rpx; |
||||
|
text-align: center; |
||||
|
@include flcw(22upx, 32upx, #fff); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.gi-txt-info{ |
||||
|
padding: 20rpx 30rpx; |
||||
|
background-color: #fff; |
||||
|
.gti-price{ |
||||
|
display: flex; |
||||
|
align-items: baseline; |
||||
|
.gp-sell{ |
||||
|
@include flcw(48upx, 66upx, #FF873D, 500); |
||||
|
@include tHide; |
||||
|
} |
||||
|
.gp-del{ |
||||
|
margin-left: 44rpx; |
||||
|
flex-shrink: 0; |
||||
|
max-width: 30%; |
||||
|
text-decoration: line-through; |
||||
|
@include flcw(24rpx, 34upx, #9C9C9F); |
||||
|
@include tHide; |
||||
|
} |
||||
|
} |
||||
|
.gti-discounts{ |
||||
|
@include ctf(flex-end); |
||||
|
.gd-left{ |
||||
|
flex-grow: 1; |
||||
|
@include ctf; |
||||
|
.gl-integration{ |
||||
|
@include flcw(24rpx, 34upx, #FF873D); |
||||
|
@include tHide; |
||||
|
} |
||||
|
.gl-tag{ |
||||
|
flex-shrink: 0; |
||||
|
margin-left: 32upx; |
||||
|
text-align: center; |
||||
|
width: 58upx; |
||||
|
border-radius: 6upx; |
||||
|
border: 1px solid rgba($color: #E60213, $alpha: .5); |
||||
|
@include flcw(20upx, 28upx, #E60213); |
||||
|
} |
||||
|
} |
||||
|
.gd-right{ |
||||
|
flex-shrink: 0; |
||||
|
margin-top: 10upx; |
||||
|
margin-left: 20upx; |
||||
|
@include ctf(flex-end); |
||||
|
.gr-txt{ |
||||
|
@include flcw(24rpx, 34upx, #FF873D); |
||||
|
} |
||||
|
.gr-img{ |
||||
|
width: 28rpx; |
||||
|
height: 28rpx; |
||||
|
margin-left: 10rpx; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
.gti-bottom{ |
||||
|
margin-top: 20upx; |
||||
|
@include ctf; |
||||
|
.gb-left{ |
||||
|
flex-grow: 1; |
||||
|
.gb-name{ |
||||
|
@include flcw(28rpx, 40rpx, #333, 500); |
||||
|
@include tHide(2); |
||||
|
} |
||||
|
.gb-desc{ |
||||
|
@include flcw(24rpx, 34upx, #9c9c9f); |
||||
|
@include tHide(2); |
||||
|
} |
||||
|
} |
||||
|
.gb-right{ |
||||
|
margin-left: 20upx; |
||||
|
flex-shrink: 0; |
||||
|
max-width: 25%; |
||||
|
.gr-num{ |
||||
|
text-align: center; |
||||
|
@include flcw(36rpx, 42upx, #333, 700); |
||||
|
@include tHide; |
||||
|
} |
||||
|
.gr-star-ls{ |
||||
|
margin-top: 10upx; |
||||
|
@include ctf(center); |
||||
|
.gsl-img{ |
||||
|
width: 28upx; |
||||
|
height: 28upx; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.gi-selected{ |
||||
|
margin-top: 20rpx; |
||||
|
padding: 20rpx 30rpx 20rpx 26rpx; |
||||
|
background: #fff; |
||||
|
.gs-item{ |
||||
|
padding: 20rpx 0; |
||||
|
@include ctf; |
||||
|
.gs-name{ |
||||
|
flex-shrink: 0; |
||||
|
margin-right: 40rpx; |
||||
|
@include flcw(24upx, 34upx, #9a9a9d); |
||||
|
} |
||||
|
.gs-content{ |
||||
|
flex-grow: 1; |
||||
|
font-size: 0; |
||||
|
@include tHide; |
||||
|
.gc-icon{ |
||||
|
margin-right: 8upx; |
||||
|
margin-bottom: -2rpx; |
||||
|
vertical-align: baseline; |
||||
|
width: 24rpx; |
||||
|
height: 24rpx; |
||||
|
} |
||||
|
.gc-txt{ |
||||
|
@include flcw(24upx, 34upx, #333); |
||||
|
&+.gc-icon{ |
||||
|
margin-left: 16upx; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
.gs-icon{ |
||||
|
flex-shrink: 0; |
||||
|
margin-left: 20upx; |
||||
|
width: 28rpx; |
||||
|
height: 28rpx; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
.gi-detail{ |
||||
|
margin-top: 20rpx; |
||||
|
background-color: #fff; |
||||
|
.gd-title{ |
||||
|
padding: 40upx 0; |
||||
|
@include ctf(center); |
||||
|
.gt-icon{ |
||||
|
@include ctf; |
||||
|
&::before, &::after{ |
||||
|
content: ''; |
||||
|
display: block; |
||||
|
background-color: #d8d8d8; |
||||
|
} |
||||
|
&::before{ |
||||
|
width: 60rpx; |
||||
|
height: 2rpx; |
||||
|
} |
||||
|
&::after{ |
||||
|
transform: translateX(-50%); |
||||
|
width: 8rpx; |
||||
|
height: 8rpx; |
||||
|
border-radius: 8rpx; |
||||
|
} |
||||
|
} |
||||
|
.gt-txt{ |
||||
|
margin: 0 40rpx; |
||||
|
@include flcw(28upx, 40upx, #333); |
||||
|
&+.gt-icon{ |
||||
|
flex-direction: row-reverse; |
||||
|
&::after{ |
||||
|
transform: translateX(50%); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
.gd-rich-txt{ |
||||
|
margin-top: 50upx; |
||||
|
padding-bottom: 30upx; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.gd-fixed-bar{ |
||||
|
position: fixed; |
||||
|
left: 0; |
||||
|
bottom: 0; |
||||
|
width: 100%; |
||||
|
padding: 20upx 24upx 10upx; |
||||
|
background: #fff; |
||||
|
@include isPd(10upx); |
||||
|
@include ctf(space-between); |
||||
|
.gfb-left{ |
||||
|
@include ctf; |
||||
|
flex-grow: 1; |
||||
|
.gl-box{ |
||||
|
position: relative; |
||||
|
font-size: 0; |
||||
|
text-align: center; |
||||
|
&+.gl-box{ |
||||
|
margin-left: 26upx; |
||||
|
} |
||||
|
.gb-icon{ |
||||
|
display: block; |
||||
|
margin: 0 auto; |
||||
|
width: 48upx; |
||||
|
height: 48upx; |
||||
|
} |
||||
|
.gb-txt{ |
||||
|
margin-top: 2upx; |
||||
|
text-align: center; |
||||
|
@include flcw(20upx, 28upx, #9A9A9D, 500); |
||||
|
} |
||||
|
.gb-num{ |
||||
|
position: absolute; |
||||
|
right: -20upx; |
||||
|
top: -8upx; |
||||
|
width: 36rpx; |
||||
|
text-align: center; |
||||
|
border-radius: 36rpx; |
||||
|
background-color: #e60213; |
||||
|
@include flcw(22rpx, 36rpx, #fff); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
.gfb-btns{ |
||||
|
flex-shrink: 0; |
||||
|
@include ctf(flex-end); |
||||
|
.gb-item{ |
||||
|
width: 260rpx; |
||||
|
border-radius: 44rpx; |
||||
|
border: 2rpx solid #009874; |
||||
|
text-align: center; |
||||
|
@include flcw(32rpx, 84upx, $mColor, 500); |
||||
|
&+.gb-item{ |
||||
|
margin-left: 20upx; |
||||
|
border-width: 0upx; |
||||
|
line-height: 88upx; |
||||
|
color: #fff; |
||||
|
background: linear-gradient(90deg, #44d7b6 0%, #009874 100%); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
After Width: 28 | Height: 30 | Size: 237 B |
After Width: 28 | Height: 30 | Size: 242 B |
After Width: 48 | Height: 48 | Size: 1.2 KiB |
After Width: 24 | Height: 26 | Size: 701 B |
After Width: 56 | Height: 56 | Size: 2.1 KiB |
After Width: 48 | Height: 48 | Size: 1.7 KiB |
After Width: 28 | Height: 30 | Size: 362 B |