1、隐藏商品的评论和保障

2、更换导航栏的发布为买酱料,首页为找档口
3、分享打印判断
4、增加法律声明页面的配置
This commit is contained in:
wangzimeng 2025-08-13 14:55:45 +08:00
parent 002a9c79af
commit 53d6123af9
5 changed files with 389 additions and 381 deletions

View File

@ -21,13 +21,13 @@
} }
}, },
{ {
"path": "pages/index/fabu", "path": "pages/index/category",
"style": { "style": {
"navigationBarTitleText": "发布信息" "navigationBarTitleText": "商品分类"
}, },
"meta": { "meta": {
"sync": true, "sync": true,
"title": "发布信息", "title": "商品分类",
"group": "商城" "group": "商城"
} }
}, },
@ -43,13 +43,13 @@
} }
}, },
{ {
"path": "pages/index/category", "path": "pages/index/fabu",
"style": { "style": {
"navigationBarTitleText": "商品分类" "navigationBarTitleText": "发布信息"
}, },
"meta": { "meta": {
"sync": true, "sync": true,
"title": "商品分类", "title": "发布信息",
"group": "商城" "group": "商城"
} }
}, },
@ -169,6 +169,17 @@
"group": "商品" "group": "商品"
} }
}, },
{
"path": "lawNotice",
"style": {
"navigationBarTitleText": "法律声明"
},
"meta": {
"sync": true,
"title": "法律声明",
"group": "商品"
}
},
{ {
"path": "groupon", "path": "groupon",
"style": { "style": {
@ -854,7 +865,7 @@
"pagePath": "pages/index/index" "pagePath": "pages/index/index"
}, },
{ {
"pagePath": "pages/index/fabu" "pagePath": "pages/index/category"
}, },
{ {
"pagePath": "pages/index/user" "pagePath": "pages/index/user"

View File

@ -1,417 +1,386 @@
<template> <template>
<view> <view>
<s-layout :onShareAppMessage="shareInfo" navbar="goods"> <s-layout :onShareAppMessage="shareInfo" navbar="goods">
<!-- 标题栏 --> <!-- 标题栏 -->
<detailNavbar /> <detailNavbar />
<!-- 骨架屏 --> <!-- 骨架屏 -->
<detailSkeleton v-if="state.skeletonLoading" /> <detailSkeleton v-if="state.skeletonLoading" />
<!-- 下架/售罄提醒 --> <!-- 下架/售罄提醒 -->
<s-empty <s-empty v-else-if="state.goodsInfo === null" text="商品不存在或已下架" icon="/static/soldout-empty.png" showAction
v-else-if="state.goodsInfo === null" actionText="再逛逛" actionUrl="/pages/goods/list" />
text="商品不存在或已下架" <block v-else>
icon="/static/soldout-empty.png" <view class="detail-swiper-selector">
showAction <!-- 商品轮播图 -->
actionText="再逛逛" <su-swiper class="ss-m-b-14" isPreview :list="state.goodsSwiper" dotStyle="tag" imageMode="widthFix"
actionUrl="/pages/goods/list" dotCur="bg-mask-40" :seizeHeight="750" />
/>
<block v-else>
<view class="detail-swiper-selector">
<!-- 商品轮播图 -->
<su-swiper
class="ss-m-b-14"
isPreview
:list="state.goodsSwiper"
dotStyle="tag"
imageMode="widthFix"
dotCur="bg-mask-40"
:seizeHeight="750"
/>
<!-- 价格+标题 --> <!-- 价格+标题 -->
<view class="title-card detail-card ss-p-y-40 ss-p-x-20"> <view class="title-card detail-card ss-p-y-40 ss-p-x-20">
<view class="ss-flex ss-row-between ss-col-center ss-m-b-26"> <view class="ss-flex ss-row-between ss-col-center ss-m-b-26">
<view class="price-box ss-flex ss-col-bottom"> <view class="price-box ss-flex ss-col-bottom">
<view class="price-text ss-m-r-16"> <view class="price-text ss-m-r-16">
{{ state.selectedSkuPrice.price || formatPrice(state.goodsInfo.price) }} {{ state.selectedSkuPrice.price || formatPrice(state.goodsInfo.price) }}
</view> </view>
<view class="origin-price-text" v-if="state.goodsInfo.original_price > 0"> <view class="origin-price-text" v-if="state.goodsInfo.original_price > 0">
{{ state.selectedSkuPrice.original_price || state.goodsInfo.original_price }} {{ state.selectedSkuPrice.original_price || state.goodsInfo.original_price }}
</view> </view>
</view> </view>
<view class="sales-text"> <view class="sales-text">
{{ formatSales(state.goodsInfo.sales_show_type, state.goodsInfo.sales) }} {{ formatSales(state.goodsInfo.sales_show_type, state.goodsInfo.sales) }}
</view> </view>
</view> </view>
<view class="discounts-box ss-flex ss-row-between ss-m-b-28"> <view class="discounts-box ss-flex ss-row-between ss-m-b-28">
<div class="tag-content"> <div class="tag-content">
<view class="tag-box ss-flex"> <view class="tag-box ss-flex">
<view <view class="tag ss-m-r-10" v-for="promos in state.goodsInfo.promos"
class="tag ss-m-r-10" :key="promos.id" @tap="onActivity">
v-for="promos in state.goodsInfo.promos" {{ promos.title }}
:key="promos.id" </view>
@tap="onActivity" </view>
> </div>
{{ promos.title }}
</view>
</view>
</div>
<view <view class="get-coupon-box ss-flex ss-col-center ss-m-l-20" @tap="state.showModel = true"
class="get-coupon-box ss-flex ss-col-center ss-m-l-20" v-if="state.couponInfo.length">
@tap="state.showModel = true" <view class="discounts-title ss-m-r-8">领券</view>
v-if="state.couponInfo.length" <text class="cicon-forward"></text>
> </view>
<view class="discounts-title ss-m-r-8">领券</view> </view>
<text class="cicon-forward"></text> <view class="title-text ss-line-2 ss-m-b-6">{{ state.goodsInfo.title }}</view>
</view> <view class="subtitle-text ss-line-1">{{ state.goodsInfo.subtitle }}</view>
</view> </view>
<view class="title-text ss-line-2 ss-m-b-6">{{ state.goodsInfo.title }}</view>
<view class="subtitle-text ss-line-1">{{ state.goodsInfo.subtitle }}</view>
</view>
<!-- 功能卡片 --> <!-- 功能卡片 -->
<view class="detail-cell-card detail-card ss-flex-col"> <view class="detail-cell-card detail-card ss-flex-col">
<detail-cell-sku <detail-cell-sku v-model="state.selectedSkuPrice.goods_sku_text" :skus="state.goodsInfo.skus"
v-model="state.selectedSkuPrice.goods_sku_text" @tap="state.showSelectSku = true" />
:skus="state.goodsInfo.skus" <!-- <detail-cell-service v-if="state.goodsInfo.service" v-model="state.goodsInfo.service" /> -->
@tap="state.showSelectSku = true" <detail-cell-params v-if="state.goodsInfo.params" v-model="state.goodsInfo.params" />
/> </view>
<detail-cell-service v-if="state.goodsInfo.service" v-model="state.goodsInfo.service" />
<detail-cell-params v-if="state.goodsInfo.params" v-model="state.goodsInfo.params" />
</view>
<!-- 规格与数量弹框 --> <!-- 规格与数量弹框 -->
<s-select-sku <s-select-sku :goodsInfo="state.goodsInfo" :show="state.showSelectSku" @addCart="onAddCart"
:goodsInfo="state.goodsInfo" @buy="onBuy" @change="onSkuChange" @close="state.showSelectSku = false" />
:show="state.showSelectSku" </view>
@addCart="onAddCart"
@buy="onBuy"
@change="onSkuChange"
@close="state.showSelectSku = false"
/>
</view>
<!-- 评价 --> <!-- 评价 -->
<detail-comment-card class="detail-comment-selector" :goodsId="state.goodsId" /> <!-- <detail-comment-card class="detail-comment-selector" :goodsId="state.goodsId" /> -->
<!-- 详情 --> <!-- 详情 -->
<detail-content-card class="detail-content-selector" :content="state.goodsInfo.content" /> <detail-content-card class="detail-content-selector" :content="state.goodsInfo.content" />
<!-- 活动跳转 --> <!-- 活动跳转 -->
<detail-activity-tip <detail-activity-tip v-if="state.goodsInfo.activities" :data="state.goodsInfo"></detail-activity-tip>
v-if="state.goodsInfo.activities"
:data="state.goodsInfo"
></detail-activity-tip>
<!-- 详情tabbar --> <!-- 详情tabbar -->
<detail-tabbar v-model="state.goodsInfo"> <detail-tabbar v-model="state.goodsInfo">
<!-- TODO: 缺货中 已售罄 判断 设计--> <!-- TODO: 缺货中 已售罄 判断 设计-->
<view class="buy-box ss-flex ss-col-center ss-p-r-20" v-if="state.goodsInfo.stock > 0"> <view class="buy-box ss-flex ss-col-center ss-p-r-20" v-if="state.goodsInfo.stock > 0">
<button <button class="ss-reset-button add-btn ui-Shadow-Main" @tap="state.showSelectSku = true">
class="ss-reset-button add-btn ui-Shadow-Main" 加入购物车
@tap="state.showSelectSku = true" </button>
> <button class="ss-reset-button buy-btn ui-Shadow-Main" @tap="state.showSelectSku = true">
加入购物车 立即购买
</button> </button>
<button </view>
class="ss-reset-button buy-btn ui-Shadow-Main" <view class="buy-box ss-flex ss-col-center ss-p-r-20" v-else>
@tap="state.showSelectSku = true" <button class="ss-reset-button disabled-btn" disabled> 已售罄 </button>
> </view>
立即购买 </detail-tabbar>
</button> <s-coupon-get v-model="state.couponInfo" :show="state.showModel" @close="state.showModel = false"
</view> @get="onGet" />
<view class="buy-box ss-flex ss-col-center ss-p-r-20" v-else> <s-activity-pop v-model="state.activityInfo" :show="state.showActivityModel"
<button class="ss-reset-button disabled-btn" disabled> 已售罄 </button> @close="state.showActivityModel = false" />
</view> </block>
</detail-tabbar> </s-layout>
<s-coupon-get </view>
v-model="state.couponInfo"
:show="state.showModel"
@close="state.showModel = false"
@get="onGet"
/>
<s-activity-pop
v-model="state.activityInfo"
:show="state.showActivityModel"
@close="state.showActivityModel = false"
/>
</block>
</s-layout>
</view>
</template> </template>
<script setup> <script setup>
import { reactive, computed } from 'vue'; import {
import { onLoad, onPageScroll } from '@dcloudio/uni-app'; reactive,
import sheep from '@/sheep'; computed
import { formatSales, formatGoodsSwiper, formatPrice } from '@/sheep/hooks/useGoods'; } from 'vue';
import detailNavbar from './components/detail/detail-navbar.vue'; import {
import detailCellSku from './components/detail/detail-cell-sku.vue'; onLoad,
import detailCellService from './components/detail/detail-cell-service.vue'; onPageScroll
import detailCellParams from './components/detail/detail-cell-params.vue'; } from '@dcloudio/uni-app';
import detailTabbar from './components/detail/detail-tabbar.vue'; import sheep from '@/sheep';
import detailSkeleton from './components/detail/detail-skeleton.vue'; import {
import detailCommentCard from './components/detail/detail-comment-card.vue'; formatSales,
import detailContentCard from './components/detail/detail-content-card.vue'; formatGoodsSwiper,
import detailActivityTip from './components/detail/detail-activity-tip.vue'; formatPrice
import { isEmpty } from 'lodash'; } from '@/sheep/hooks/useGoods';
import detailNavbar from './components/detail/detail-navbar.vue';
import detailCellSku from './components/detail/detail-cell-sku.vue';
import detailCellService from './components/detail/detail-cell-service.vue';
import detailCellParams from './components/detail/detail-cell-params.vue';
import detailTabbar from './components/detail/detail-tabbar.vue';
import detailSkeleton from './components/detail/detail-skeleton.vue';
import detailCommentCard from './components/detail/detail-comment-card.vue';
import detailContentCard from './components/detail/detail-content-card.vue';
import detailActivityTip from './components/detail/detail-activity-tip.vue';
import {
isEmpty
} from 'lodash';
// import detailActivityTip from './components/detail/detail-activity-tip.vue'; // import detailActivityTip from './components/detail/detail-activity-tip.vue';
// import detailTab from './components/detail/detail-tab.vue'; // import detailTab from './components/detail/detail-tab.vue';
// import detailCoupon from './components/detail/detail-coupon.vue'; // import detailCoupon from './components/detail/detail-coupon.vue';
onPageScroll(() => {}); onPageScroll(() => {});
const state = reactive({ const state = reactive({
goodsId: 0, goodsId: 0,
skeletonLoading: true, skeletonLoading: true,
goodsInfo: {}, goodsInfo: {},
showSelectSku: false, showSelectSku: false,
goodsSwiper: [], goodsSwiper: [],
selectedSkuPrice: {}, selectedSkuPrice: {},
showModel: false, showModel: false,
total: 0, total: 0,
couponInfo: [], couponInfo: [],
showActivityModel: false, showActivityModel: false,
activityInfo: [], activityInfo: [],
}); });
// //
function onSkuChange(e) { function onSkuChange(e) {
state.selectedSkuPrice = e; state.selectedSkuPrice = e;
} }
// //
function onAddCart(e) { function onAddCart(e) {
sheep.$store('cart').add(e); sheep.$store('cart').add(e);
} }
// //
function onBuy(e) { function onBuy(e) {
sheep.$router.go('/pages/order/confirm', { sheep.$router.go('/pages/order/confirm', {
data: JSON.stringify({ data: JSON.stringify({
order_type: 'goods', order_type: 'goods',
goods_list: [ goods_list: [{
{ goods_id: e.goods_id,
goods_id: e.goods_id, goods_num: e.goods_num,
goods_num: e.goods_num, goods_sku_price_id: e.id,
goods_sku_price_id: e.id, }, ],
}, }),
], });
}), }
}); //
} function onActivity() {
// state.activityInfo = state.goodsInfo.promos;
function onActivity() { state.showActivityModel = true;
state.activityInfo = state.goodsInfo.promos; }
state.showActivityModel = true;
}
// //
async function onGet(id) { async function onGet(id) {
const { code, msg } = await sheep.$api.coupon.get(id); const {
if (code === 1) { code,
uni.showToast({ msg
title: msg, } = await sheep.$api.coupon.get(id);
}); if (code === 1) {
setTimeout(() => { uni.showToast({
getCoupon(); title: msg,
}, 1000); });
} setTimeout(() => {
} getCoupon();
}, 1000);
}
}
const shareInfo = computed(() => { const shareInfo = computed(() => {
if (isEmpty(state.goodsInfo)) return {}; if (isEmpty(state.goodsInfo)) return {};
return sheep.$platform.share.getShareInfo( return sheep.$platform.share.getShareInfo({
{ title: state.goodsInfo.title,
title: state.goodsInfo.title, image: sheep.$url.cdn(state.goodsInfo.image),
image: sheep.$url.cdn(state.goodsInfo.image), desc: state.goodsInfo.subtitle,
desc: state.goodsInfo.subtitle, params: {
params: { page: '2',
page: '2', query: state.goodsInfo.id,
query: state.goodsInfo.id, },
}, }, {
}, type: 'goods', //
{ title: state.goodsInfo.title, //
type: 'goods', // image: sheep.$url.cdn(state.goodsInfo.image), //
title: state.goodsInfo.title, // price: state.goodsInfo.price[0], //
image: sheep.$url.cdn(state.goodsInfo.image), // original_price: state.goodsInfo.original_price, //
price: state.goodsInfo.price[0], // }, );
original_price: state.goodsInfo.original_price, // });
},
);
});
onLoad(async (options) => { onLoad(async (options) => {
// //
if (!options.id) { if (!options.id) {
state.goodsInfo = null; state.goodsInfo = null;
return; return;
} }
state.goodsId = options.id; state.goodsId = options.id;
// //
sheep.$api.goods.detail(state.goodsId).then((res) => { sheep.$api.goods.detail(state.goodsId).then((res) => {
state.skeletonLoading = false; state.skeletonLoading = false;
if (res.code === 1) { if (res.code === 1) {
state.goodsInfo = res.data; state.goodsInfo = res.data;
state.goodsSwiper = formatGoodsSwiper(state.goodsInfo.images); state.goodsSwiper = formatGoodsSwiper(state.goodsInfo.images);
} else { } else {
// //
state.goodsInfo = null; state.goodsInfo = null;
} }
}); });
const { code, data } = await sheep.$api.coupon.listByGoods(state.goodsId); const {
if (code === 1) { code,
state.couponInfo = data; data
} } = await sheep.$api.coupon.listByGoods(state.goodsId);
}); if (code === 1) {
state.couponInfo = data;
}
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.detail-card {
background-color: #ffff;
margin: 14rpx 20rpx;
border-radius: 10rpx;
overflow: hidden;
}
// .detail-card {
.title-card { background-color: #ffff;
.price-box { margin: 14rpx 20rpx;
.price-text { border-radius: 10rpx;
font-size: 42rpx; overflow: hidden;
font-weight: 500; }
color: #ff3000;
line-height: 30rpx;
font-family: OPPOSANS;
&::before { //
content: '¥'; .title-card {
font-size: 30rpx; .price-box {
} .price-text {
} font-size: 42rpx;
font-weight: 500;
color: #ff3000;
line-height: 30rpx;
font-family: OPPOSANS;
.origin-price-text { &::before {
font-size: 26rpx; content: '¥';
font-weight: 400; font-size: 30rpx;
text-decoration: line-through; }
color: $gray-c; }
font-family: OPPOSANS;
&::before { .origin-price-text {
content: '¥'; font-size: 26rpx;
} font-weight: 400;
} text-decoration: line-through;
} color: $gray-c;
font-family: OPPOSANS;
.sales-text { &::before {
font-size: 26rpx; content: '¥';
font-weight: 500; }
color: $gray-c; }
} }
.discounts-box { .sales-text {
.tag-content { font-size: 26rpx;
flex: 1; font-weight: 500;
min-width: 0; color: $gray-c;
white-space: nowrap; }
}
.tag-box { .discounts-box {
overflow: hidden; .tag-content {
text-overflow: ellipsis; flex: 1;
} min-width: 0;
white-space: nowrap;
}
.tag { .tag-box {
flex-shrink: 0; overflow: hidden;
padding: 4rpx 10rpx; text-overflow: ellipsis;
font-size: 24rpx; }
font-weight: 500;
border-radius: 4rpx;
color: var(--ui-BG-Main);
background: var(--ui-BG-Main-tag);
}
.discounts-title { .tag {
font-size: 24rpx; flex-shrink: 0;
font-weight: 500; padding: 4rpx 10rpx;
color: var(--ui-BG-Main); font-size: 24rpx;
line-height: normal; font-weight: 500;
} border-radius: 4rpx;
color: var(--ui-BG-Main);
background: var(--ui-BG-Main-tag);
}
.cicon-forward { .discounts-title {
color: var(--ui-BG-Main); font-size: 24rpx;
font-size: 24rpx; font-weight: 500;
line-height: normal; color: var(--ui-BG-Main);
margin-top: 4rpx; line-height: normal;
} }
}
.title-text { .cicon-forward {
font-size: 30rpx; color: var(--ui-BG-Main);
font-weight: bold; font-size: 24rpx;
line-height: 42rpx; line-height: normal;
} margin-top: 4rpx;
}
}
.subtitle-text { .title-text {
font-size: 26rpx; font-size: 30rpx;
font-weight: 400; font-weight: bold;
color: $dark-9; line-height: 42rpx;
line-height: 42rpx; }
}
}
// .subtitle-text {
.buy-box { font-size: 26rpx;
.add-btn { font-weight: 400;
width: 214rpx; color: $dark-9;
height: 72rpx; line-height: 42rpx;
font-weight: 500; }
font-size: 28rpx; }
border-radius: 40rpx 0 0 40rpx;
background-color: var(--ui-BG-Main-light);
color: var(--ui-BG-Main);
}
.buy-btn { //
width: 214rpx; .buy-box {
height: 72rpx; .add-btn {
font-weight: 500; width: 214rpx;
font-size: 28rpx; height: 72rpx;
font-weight: 500;
font-size: 28rpx;
border-radius: 40rpx 0 0 40rpx;
background-color: var(--ui-BG-Main-light);
color: var(--ui-BG-Main);
}
border-radius: 0 40rpx 40rpx 0; .buy-btn {
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient)); width: 214rpx;
color: $white; height: 72rpx;
} font-weight: 500;
font-size: 28rpx;
.disabled-btn { border-radius: 0 40rpx 40rpx 0;
width: 428rpx; background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
height: 72rpx; color: $white;
font-weight: 500; }
font-size: 28rpx;
border-radius: 0 40rpx 40rpx 0; .disabled-btn {
background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient)); width: 428rpx;
color: $white; height: 72rpx;
} font-weight: 500;
} font-size: 28rpx;
.model-box { border-radius: 0 40rpx 40rpx 0;
height: 60vh; background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
color: $white;
}
}
.model-content { .model-box {
height: 56vh; height: 60vh;
}
.title { .model-content {
font-size: 36rpx; height: 56vh;
font-weight: bold; }
color: #333333;
}
.subtitle { .title {
font-size: 26rpx; font-size: 36rpx;
font-weight: 500; font-weight: bold;
color: #333333; color: #333333;
} }
}
.subtitle {
font-size: 26rpx;
font-weight: 500;
color: #333333;
}
}
</style> </style>

25
pages/goods/lawNotice.vue Normal file
View File

@ -0,0 +1,25 @@
<template>
<s-layout title="法律声明">
<view style="padding: 30rpx;">
<rich-text style="text-align: justify;" :nodes="Negotiate"></rich-text>
</view>
</s-layout>
</template>
<script setup>
import { ref,reactive } from 'vue'
import {
onLoad,
onShow,
onPageScroll,
onPullDownRefresh,
onReachBottom
} from '@dcloudio/uni-app';
import sheep from '@/sheep';
</script>
<style lang="scss" scoped>
</style>

View File

@ -1,6 +1,6 @@
<template> <template>
<!-- tabbar="/pages/index/category" --> <!-- tabbar="/pages/index/category" -->
<s-layout title="分类" :bgStyle="{ color: '#fff' }"> <s-layout title="分类" tabbar="/pages/index/category" :bgStyle="{ color: '#fff' }">
<view class="s-category"> <view class="s-category">
<view class="three-level-wrap ss-flex ss-col-top"> <view class="three-level-wrap ss-flex ss-col-top">
<view class="side-menu-wrap" :style="[{ top: Number(statusBarHeight + 88) + 'rpx' }]"> <view class="side-menu-wrap" :style="[{ top: Number(statusBarHeight + 88) + 'rpx' }]">

View File

@ -47,6 +47,7 @@ const getShareInfo = (
// 配置转发参数 // 配置转发参数
if (shareConfig.methods.includes('forward')) { if (shareConfig.methods.includes('forward')) {
console.log('shareConfig');
if (shareConfig.forwardInfo.title === '' || shareConfig.forwardInfo.image === '') { if (shareConfig.forwardInfo.title === '' || shareConfig.forwardInfo.image === '') {
console.log('请在平台设置中配置转发信息'); console.log('请在平台设置中配置转发信息');
} }
@ -148,11 +149,13 @@ const decryptSpm = (spm) => {
}; };
break; break;
} }
shareParams.platform = platformMap[shareParamsArray[3] - 1]; shareParams.platform = platformMap[shareParamsArray[3] - 1];
shareParams.from = fromMap[shareParamsArray[4] - 1]; shareParams.from = fromMap[shareParamsArray[4] - 1];
if (shareParams.shareId != 0) { if (shareParams.shareId != 0) {
// 已登录 立即添加分享记录 // 已登录 立即添加分享记录
if (user.isLogin) { if (user.isLogin) {
console.log('已登录 立即添加分享记录前');
user.addShareLog(shareParams); user.addShareLog(shareParams);
} else { } else {
// 未登录 待用户登录后添加分享记录 // 未登录 待用户登录后添加分享记录