Merge pull request 'Branch_ccc' (#4) from Branch_ccc into master

Reviewed-on: #4
This commit is contained in:
root 2024-10-09 13:58:40 +08:00
commit 1b6dbfcb5d
63 changed files with 6986 additions and 1629 deletions

3
.env
View File

@ -3,10 +3,11 @@ SHOPRO_VERSION = v1.8.3
# 后端接口 - 正式环境(通过 process.env.NODE_ENV 非 development
SHOPRO_BASE_URL = https://zysc.fjptzykj.com
#SHOPRO_BASE_URL = http://192.168.1.20:6127
# 后端接口 - 测试环境(通过 process.env.NODE_ENV = development
SHOPRO_DEV_BASE_URL = https://zysc.fjptzykj.com
### SHOPRO_DEV_BASE_URL = http://yunai.natapp1.cc
#SHOPRO_DEV_BASE_URL = http://192.168.1.20:6127
# 后端接口前缀(一般不建议调整)
SHOPRO_API_PATH = /app-api

View File

@ -20,6 +20,32 @@
"group": "商城"
}
},
{
"path": "pages/integration/index",
"style": {
"navigationBarTitleText": "积分商城",
"enablePullDownRefresh": true
},
"meta": {
"auth": false,
"sync": true,
"title": "积分商城",
"group": "商城"
}
},
{
"path": "pages/subscribe/subscribe",
"style": {
"navigationBarTitleText": "预约",
"enablePullDownRefresh": true
},
"meta": {
"auth": false,
"sync": true,
"title": "预约",
"group": "商城"
}
},
{
"path": "pages/index/user",
"style": {
@ -121,8 +147,7 @@
},
{
"path": "pages/mulu/mulu",
"style" :
{
"style": {
"navigationBarTitleText": "详情",
"enablePullDownRefresh": true,
"navigationStyle": "default"
@ -165,6 +190,28 @@
"group": "商品"
}
},
{
"path": "point",
"style": {
"navigationBarTitleText": "积分商品"
},
"meta": {
"sync": true,
"title": "积分商品",
"group": "商品"
}
},
{
"path": "sales",
"style": {
"navigationBarTitleText": "促销商品"
},
"meta": {
"sync": true,
"title": "促销商品",
"group": "商品"
}
},
{
"path": "list",
"style": {
@ -306,6 +353,18 @@
"group": "用户中心"
}
},
{
"path": "user_vip/index",
"style": {
"navigationBarTitleText": "会员中心"
},
"meta": {
"auth": true,
"sync": true,
"title": "会员中心",
"group": "用户中心"
}
},
{
"path": "goods-collect",
"style": {
@ -352,6 +411,16 @@
"title": "编辑地址"
}
},
{
"path": "goods_details_store/index",
"style": {
"navigationBarTitleText": "门店管理"
},
"meta": {
"auth": true,
"title": "门店管理"
}
},
{
"path": "wallet/money",
"style": {

View File

@ -1,37 +1,23 @@
<!-- 拼团订单的详情 -->
<template>
<s-layout
title="拼团详情"
class="detail-wrap"
:navbar="state.data && !state.loading ? 'inner' : 'normal'"
:onShareAppMessage="shareInfo"
>
<s-layout title="拼团详情" class="detail-wrap" :navbar="state.data && !state.loading ? 'inner' : 'normal'">
<!-- :onShareAppMessage="shareInfo" -->
<view v-if="state.loading"></view>
<view v-if="state.data && !state.loading">
<!-- 团长信息 + 活动信息 -->
<view
class="recharge-box"
v-if="state.data.headRecord"
:style="[
<view class="recharge-box" v-if="state.data.headRecord" :style="[
{
marginTop: '-' + Number(statusBarHeight + 88) + 'rpx',
paddingTop: Number(statusBarHeight + 108) + 'rpx',
},
]"
>
<s-goods-item
class="goods-box"
:img="state.data.headRecord.picUrl"
:title="state.data.headRecord.spuName"
:price="state.data.headRecord.combinationPrice"
priceColor="#E1212B"
@tap="
]">
<s-goods-item class="goods-box" :img="state.data.headRecord.picUrl"
:title="state.data.headRecord.spuName" :price="state.data.headRecord.combinationPrice"
priceColor="#E1212B" @tap="
sheep.$router.go('/pages/goods/groupon', {
id: state.data.headRecord.activityId,
})
"
:style="[{ top: Number(statusBarHeight + 108) + 'rpx' }]"
>
" :style="[{ top: Number(statusBarHeight + 108) + 'rpx' }]">
<template #groupon>
<view class="ss-flex">
<view class="sales-title">{{ state.data.headRecord.userSize }}人团</view>
@ -40,7 +26,8 @@
</template>
</s-goods-item>
</view>
<image class="image" mode="aspectFill"
src="https://zysc.fjptzykj.com:3000/shangcheng/2dc59ec207f1c5bd04d0f4734a4600c5e2dce8e5d740bb7ddfce75e9012a4b04.png" />
<view class="countdown-box detail-card ss-p-t-44 ss-flex-col ss-col-center">
<!-- 情况一拼团成功 -->
<view v-if="state.data.headRecord.status === 1">
@ -76,9 +63,7 @@
</view>
<view class="countdown-title ss-flex" v-else>
还差
<view class="num"
>{{ state.data.headRecord.userSize - state.data.headRecord.userCount }}</view
>
<view class="num">{{ state.data.headRecord.userSize - state.data.headRecord.userCount }}</view>
拼团成功
<view class="ss-flex countdown-time">
<view class="countdown-h ss-flex ss-row-center">{{ endTime.h }}</view>
@ -102,43 +87,25 @@
<view class="header-tag ss-flex ss-col-center ss-row-center">团长</view>
</view>
<!-- 团员 -->
<view
class="header-avatar ss-m-r-24 ss-m-b-20"
v-for="item in state.data.memberRecords"
:key="item.id"
>
<view class="header-avatar ss-m-r-24 ss-m-b-20" v-for="item in state.data.memberRecords"
:key="item.id">
<image :src="sheep.$url.cdn(item.avatar)" class="avatar-img"></image>
<view
class="header-tag ss-flex ss-col-center ss-row-center"
v-if="item.is_leader == '1'"
>
<view class="header-tag ss-flex ss-col-center ss-row-center" v-if="item.is_leader == '1'">
团长
</view>
</view>
<!-- 还有几个坑位 -->
<view
class="default-avatar ss-m-r-24 ss-m-b-20"
v-for="item in state.remainNumber"
:key="item"
>
<image
:src="sheep.$url.static('/static/img/shop/avatar/unknown.png')"
class="avatar-img"
></image>
<view class="default-avatar ss-m-r-24 ss-m-b-20" v-for="item in state.remainNumber" :key="item">
<image :src="sheep.$url.static('/static/img/shop/avatar/unknown.png')" class="avatar-img">
</image>
</view>
</view>
</view>
<!-- 情况一拼团成功情况二拼团失败 -->
<view
v-if="state.data.headRecord.status === 1 || state.data.headRecord.status === 2"
class="ss-m-t-40 ss-flex ss-row-center"
>
<button
class="ss-reset-button order-btn"
v-if="state.data.orderId"
@tap="onDetail(state.data.orderId)"
>
<view v-if="state.data.headRecord.status === 1 || state.data.headRecord.status === 2"
class="ss-m-t-40 ss-flex ss-row-center">
<button class="ss-reset-button order-btn" v-if="state.data.orderId" @tap="onDetail(state.data.orderId)">
查看订单
</button>
<button class="ss-reset-button join-btn" v-else @tap="onCreateGroupon"> 我要开团 </button>
@ -147,19 +114,11 @@
<!-- 情况三拼团进行中查看订单或参加或邀请好友或参加 -->
<view v-if="state.data.headRecord.status === 0" class="ss-m-t-40 ss-flex ss-row-center">
<view v-if="state.data.headRecord.expireTime <= new Date().getTime()">
<button
class="ss-reset-button join-btn"
v-if="state.data.orderId"
@tap="onDetail(state.data.orderId)"
>
<button class="ss-reset-button join-btn" v-if="state.data.orderId"
@tap="onDetail(state.data.orderId)">
查看订单
</button>
<button
class="ss-reset-button disabled-btn"
v-else
disabled
@tap="onDetail(state.data.orderId)"
>
<button class="ss-reset-button disabled-btn" v-else disabled @tap="onDetail(state.data.orderId)">
去参团
</button>
</view>
@ -170,11 +129,7 @@
</button>
</view>
<view v-else>
<button
class="ss-reset-button join-btn"
:disabled="endTime.ms <= 0"
@tap="onJoinGroupon()"
>
<button class="ss-reset-button join-btn" :disabled="endTime.ms <= 0" @tap="onJoinGroupon()">
立即参团
</button>
</view>
@ -182,17 +137,9 @@
</view>
<!-- TODO 芋艿这里暂时没接入 -->
<view v-if="state.data.goods">
<s-select-groupon-sku
:show="state.showSelectSku"
:goodsInfo="state.data.goods"
:grouponAction="state.grouponAction"
:grouponNum="state.grouponNum"
@buy="onBuy"
@change="onSkuChange"
@close="state.showSelectSku = false"
/>
</view>
<s-select-groupon-sku :show="state.showSelectSku" :goodsInfo="state.goodsInfo"
:grouponAction="state.grouponAction" :grouponNum="state.grouponNum" @buy="onBuy" @change="onSkuChange"
@close="state.showSelectSku = false" />
</view>
<s-empty v-if="!state.data && !state.loading" icon="/static/goods-empty.png" />
@ -200,18 +147,32 @@
</template>
<script setup>
import { computed, reactive } from 'vue';
import {
computed,
reactive
} from 'vue';
import sheep from '@/sheep';
import { onLoad } from '@dcloudio/uni-app';
import { useDurationTime } from '@/sheep/hooks/useGoods';
import { showShareModal } from '@/sheep/hooks/useModal';
import { isEmpty } from 'lodash';
import {
onLoad
} from '@dcloudio/uni-app';
import {
useDurationTime
} from '@/sheep/hooks/useGoods';
import {
showShareModal
} from '@/sheep/hooks/useModal';
import {
isEmpty
} from 'lodash';
import CombinationApi from '@/sheep/api/promotion/combination';
import SpuApi from '@/sheep/api/product/spu';
const headerBg = sheep.$url.css('/static/img/shop/user/withdraw_bg.png');
const statusBarHeight = sheep.$platform.device.statusBarHeight * 2;
const state = reactive({
data: {}, //
data: {
goods: true
}, //
loading: true,
grouponAction: 'create',
showSelectSku: false,
@ -219,13 +180,16 @@
number: 0,
activity: {},
combinationHeadId: null, //
goodsInfo: {}, //
goodsId: '',
skeletonLoading: false,
goodsSwiper: [], //
});
// todo
const shareInfo = computed(() => {
if (isEmpty(state.data)) return {};
return sheep.$platform.share.getShareInfo(
{
return sheep.$platform.share.getShareInfo({
title: state.data.headRecord.spuName,
image: sheep.$url.cdn(state.data.headRecord.picUrl),
desc: state.data.goods?.subtitle,
@ -233,15 +197,13 @@
page: '5',
query: state.data.id,
},
},
{
}, {
type: 'groupon', //
title: state.data.headRecord.spuName, //
image: sheep.$url.cdn(state.data.headRecord.picUrl), //
price: state.data.goods?.price, //
original_price: state.data.goods?.original_price, //
},
);
}, );
});
//
@ -266,9 +228,9 @@
// TODO
function onJoinGroupon() {
state.grouponAction = 'join';
state.grouponId = state.data.activityId;
state.combinationHeadId = state.data.id;
state.grouponNum = state.data.num;
state.grouponId = state.activityId;
state.combinationHeadId = state.id;
state.grouponNum = state.userSize;
state.showSelectSku = true;
}
@ -277,32 +239,62 @@
sheep.$router.go('/pages/order/confirm', {
data: JSON.stringify({
order_type: 'goods',
combinationActivityId: state.data.activity.id,
combinationActivityId: state.grouponId,
combinationHeadId: state.combinationHeadId,
items: [
{
items: [{
skuId: sku.id,
count: sku.count,
},
],
}, ],
}),
});
}
//
const loadActiv = async () => {
//
const {
code,
data: activity
} = await CombinationApi.getCombinationActivity(state.grouponId);
state.activity = activity;
const {
data: spu
} = await SpuApi.getSpuDetail(activity.spuId);
state.goodsId = spu.id;
activity.products.forEach((product) => {
spu.price = Math.min(spu.price, product.combinationPrice); // SPU
});
//
state.skeletonLoading = false;
if (code === 0) {
state.goodsInfo = spu;
state.grouponNum = activity.userSize;
// state.goodsSwiper = formatGoodsSwiper(state.goodsInfo.sliderPicUrls);
} else {
//
state.goodsInfo = null;
}
}
const endTime = computed(() => {
return useDurationTime(state.data.headRecord.expireTime);
});
//
async function getGrouponDetail(id) {
const { code, data } = await CombinationApi.getCombinationRecordDetail(id);
const {
code,
data
} = await CombinationApi.getCombinationRecordDetail(id);
if (code === 0) {
state.data = data;
const remainNumber = Number(state.data.headRecord.userSize - state.data.headRecord.userCount);
state.remainNumber = remainNumber > 0 ? remainNumber : 0;
//
const { data: activity } = await CombinationApi.getCombinationActivity(
const {
data: activity
} = await CombinationApi.getCombinationActivity(
data.headRecord.activityId,
);
state.activity = activity;
@ -318,10 +310,28 @@
onLoad((options) => {
getGrouponDetail(options.id);
//
if (!options.id) {
state.goodsInfo = null;
return;
}
state.grouponId = options.id;
loadActiv();
});
</script>
<style lang="scss" scoped>
.image {
display: block;
margin: 0 auto;
width: 100%;
height: 154px;
}
.recharge-box {
position: relative;
margin-bottom: 120rpx;
@ -359,6 +369,7 @@
font-size: 26rpx;
font-weight: 500;
color: #383a46;
.countdown-h {
font-size: 24rpx;
font-family: OPPOSANS;
@ -370,6 +381,7 @@
background: linear-gradient(90deg, #ff6000 0%, #fe832a 100%);
border-radius: 6rpx;
}
.countdown-num {
font-size: 24rpx;
font-family: OPPOSANS;
@ -435,11 +447,13 @@
top: -36rpx;
}
}
.default-avatar {
width: 86rpx;
height: 86rpx;
background: #ececec;
border-radius: 50%;
.avatar-img {
width: 100%;
height: 100%;
@ -454,6 +468,7 @@
border-radius: 50%;
}
}
.order-btn {
width: 668rpx;
height: 70rpx;

View File

@ -119,7 +119,7 @@
width: 100%;
height: 458rpx;
margin-top: -88rpx;
background: v-bind(headerBg) no-repeat;
background: url('https://zysc.fjptzykj.com:3000/shangcheng/fea9ad54f32d4705a633874efd534e70e507030ea5a7604b0110fdf7292f1f4d.png');
background-size: 100% 100%;
}
.list-content {
@ -203,9 +203,11 @@
}
}
.scroll-box {
margin-top: 13px;
height: 900rpx;
.goods-box {
position: relative;
padding: 0 10px;
.cart-btn {
position: absolute;
bottom: 10rpx;

View File

@ -0,0 +1,76 @@
<!-- 积分商城商品列表 -->
<template>
<s-layout title="积分商城" navbar="normal" :leftWidth="0" :rightWidth="0">
<scroll-view
class="scroll-box"
:style="{ height: pageHeight + 'rpx' }"
scroll-y="true"
:scroll-with-animation="false"
:enable-back-to-top="true"
>
<s-point-card ref="sPointCardRef" class="ss-p-x-20 ss-m-t-20"/>
<s-empty
v-if="activityTotal === 0"
icon="/static/goods-empty.png"
text="暂无积分商品"
></s-empty>
<uni-load-more
v-if="activityTotal > 0"
:status="loadStatus"
:content-text="{
contentdown: '上拉加载更多',
}"
@tap="loadMore"
/>
</scroll-view>
</s-layout>
</template>
<script setup>
import sheep from '@/sheep';
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
import { reactive, ref } from 'vue';
import PointApi from '@/sheep/api/promotion/point';
import SLayout from '@/sheep/components/s-layout/s-layout.vue';
//
const { safeAreaInsets, safeArea } = sheep.$platform.device;
const statusBarHeight = sheep.$platform.device.statusBarHeight * 2;
const pageHeight =
(safeArea.height + safeAreaInsets.bottom) * 2 + statusBarHeight - sheep.$platform.navbar - 350;
const sPointCardRef = ref();
//
const activityPageParams = reactive({
pageNo: 1, //
pageSize: 5, //
});
const activityTotal = ref(0); //
const activityCount = ref(0); //
const loadStatus = ref(''); //
async function getActivityList() {
loadStatus.value = 'loading';
const { data } = await PointApi.getPointActivityPage(activityPageParams);
await sPointCardRef.value.concatActivity(data.list);
activityCount.value = sPointCardRef.value.getActivityCount();
activityTotal.value = data.total;
loadStatus.value = activityCount.value < activityTotal.value ? 'more' : 'noMore';
}
//
function loadMore() {
if (state.loadStatus !== 'noMore') {
activityPageParams.pageNo += 1;
getActivityList();
}
}
//
onReachBottom(() => {
loadMore();
});
onLoad(() => {
getActivityList();
});
</script>

View File

@ -12,7 +12,7 @@
<view class="img-wrap">
<image
class="notice-img"
:src="sheep.$url.static('/static/img/shop/commission/forbidden.png')"
src="https://zysc.fjptzykj.com:3000/shangcheng/a999baebceb39e97a8ff11c547b41bf1e78109d81532eafbd858544f86e5e159.png"
mode="aspectFill"
/>
</view>

View File

@ -34,7 +34,7 @@
height: 192rpx;
margin: -88rpx 20rpx 0 20rpx;
padding-top: 88rpx;
background: v-bind(headerBg) no-repeat;
background: url('https://zysc.fjptzykj.com:3000/shangcheng/10c7d7a9afb36266f658e5f398922b835530cb350ef98cf90d4ef6f60ccc1bc1.png') no-repeat;
background-size: 100% 100%;
.head-img-box {

View File

@ -2,7 +2,7 @@
<template>
<view class="distribution-log-wrap">
<view class="header-box">
<image class="header-bg" :src="sheep.$url.static('/static/img/shop/commission/title2.png')" />
<image class="header-bg" src="https://zysc.fjptzykj.com:3000/shangcheng/e5caf4c1869d7af8ea254a0e403848c453375bcb22f414db52a2c93a345e1e36.png" />
<view class="ss-flex header-title">
<view class="title">实时动态</view>
<text class="cicon-forward" />
@ -25,7 +25,7 @@
<view class="ss-flex ss-col-center">
<image
class="log-img"
:src="sheep.$url.static('/static/img/shop/avatar/notice.png')"
src="https://zysc.fjptzykj.com:3000/shangcheng/c4bf2f61c013c7413121274b3b75a068d992727459ba89623cc68d3521a199fe.png"
mode="aspectFill"
/>
</view>

View File

@ -2,7 +2,7 @@
<template>
<view class="menu-box ss-flex-col">
<view class="header-box">
<image class="header-bg" :src="sheep.$url.static('/static/img/shop/commission/title1.png')" />
<image class="header-bg" src="https://zysc.fjptzykj.com:3000/shangcheng/eb9244a1f0662a699869d47287a477bd16147030ff25c9573395036192b86d91.png" />
<view class="ss-flex header-title">
<view class="title">功能专区</view>
<text class="cicon-forward"></text>
@ -33,45 +33,45 @@
const state = reactive({
menuList: [
{
img: '/static/img/shop/commission/commission_icon1.png',
img: 'https://zysc.fjptzykj.com:3000/shangcheng/ec41e4f5b45c087232aab8d088019a1e9d781b9bde0f54ddbb18e90230b83255.png',
title: '我的团队',
path: '/pages/commission/team',
},
{
img: '/static/img/shop/commission/commission_icon2.png',
img: 'https://zysc.fjptzykj.com:3000/shangcheng/ec41e4f5b45c087232aab8d088019a1e9d781b9bde0f54ddbb18e90230b83255.png',
title: '佣金明细',
path: '/pages/commission/wallet',
},
{
img: '/static/img/shop/commission/commission_icon3.png',
img: 'https://zysc.fjptzykj.com:3000/shangcheng/bb763f93be24f6d5c8c2948e512b95597d748f576277cc2d91f452fb3741e5a3.png',
title: '分销订单',
path: '/pages/commission/order',
},
{
img: '/static/img/shop/commission/commission_icon4.png',
img: 'https://zysc.fjptzykj.com:3000/shangcheng/326f6fe148cd6c8328297731bd63674a3a86340f937dfd1a376e435e34b5073e.png',
title: '推广商品',
path: '/pages/commission/goods',
},
// {
// img: '/static/img/shop/commission/commission_icon5.png',
// img: 'https://zysc.fjptzykj.com:3000/shangcheng/fe729044c3c0874d93435151bb204dede3d1dfbc0e2d03d09e2f76534e7cb8ba.png',
// title: '',
// path: '/pages/commission/apply',
// isAgentFrom: true,
// },
// todo @
{
img: '/static/img/shop/commission/commission_icon7.png',
img: 'https://zysc.fjptzykj.com:3000/shangcheng/f9f9914bb3c1695055771cada0022c12bcf08fe3975485fc05ddd345c6f6e2a4.png',
title: '邀请海报',
path: 'action:showShareModal',
},
// TODO @ icon
{
// img: '/static/img/shop/commission/commission_icon7.png',
img: 'https://zysc.fjptzykj.com:3000/shangcheng/f9f9914bb3c1695055771cada0022c12bcf08fe3975485fc05ddd345c6f6e2a4.png',
title: '推广排行',
path: '/pages/commission/promoter',
},
{
// img: '/static/img/shop/commission/commission_icon7.png',
img: 'https://zysc.fjptzykj.com:3000/shangcheng/f9f9914bb3c1695055771cada0022c12bcf08fe3975485fc05ddd345c6f6e2a4.png',
title: '佣金排行',
path: '/pages/commission/commission-ranking',
},

View File

@ -351,7 +351,7 @@
width: 750rpx;
z-index: 3;
position: relative;
background: v-bind(headerBg) no-repeat,
background: url('https://zysc.fjptzykj.com:3000/shangcheng/c9aeef7e970b76991668740263d518f25ce737b1552db9ee7b22d8572a4a5110.png') no-repeat,
linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
background-size: 750rpx 100%;

View File

@ -88,12 +88,12 @@
//
.seckill-box {
background: v-bind(seckillBg) no-repeat;
background: url('https://zysc.fjptzykj.com:3000/shangcheng/0796100444273e747b7afc5778081bf8a1f8373707822cccc272cc205e7ad0f3.png') no-repeat;
background-size: 100% 100%;
}
.groupon-box {
background: v-bind(grouponBg) no-repeat;
background: url('https://zysc.fjptzykj.com:3000/shangcheng/0796100444273e747b7afc5778081bf8a1f8373707822cccc272cc205e7ad0f3.png') no-repeat;
background-size: 100% 100%;
}
</style>

File diff suppressed because one or more lines are too long

480
pages/goods/point.vue Normal file
View File

@ -0,0 +1,480 @@
<!-- 秒杀商品详情 -->
<template>
<s-layout :onShareAppMessage="shareInfo" navbar="goods">
<!-- 标题栏 -->
<detailNavbar />
<!-- 骨架屏 -->
<detailSkeleton v-if="state.skeletonLoading" />
<!-- 下架/售罄提醒 -->
<s-empty
v-else-if="state.goodsInfo === null || state.goodsInfo.activity_type !== PromotionActivityTypeEnum.POINT.type"
text="活动不存在或已结束"
icon="/static/soldout-empty.png"
showAction
actionText="再逛逛"
actionUrl="/pages/goods/list"
/>
<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="ss-flex ss-row-between ss-col-center ss-m-b-18">
<view class="price-box ss-flex ss-col-bottom">
<image
:src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
class="point-img"
></image>
<text class="point-text ss-m-r-16">
{{ getShowPrice.point }}
{{ !getShowPrice.price || getShowPrice.price === 0 ? '' : `+¥${getShowPrice.price}` }}
</text>
</view>
<view class="sales-text">
{{ formatExchange(state.goodsInfo.sales_show_type, state.goodsInfo.sales) }}
</view>
</view>
<view class="origin-price-text ss-m-b-60" v-if="state.goodsInfo.marketPrice">
原价{{ fen2yuan(state.selectedSku.marketPrice || state.goodsInfo.marketPrice) }}
</view>
<view class="title-text ss-line-2 ss-m-b-6">{{ state.goodsInfo.name || '' }}</view>
<view class="subtitle-text ss-line-1">{{ state.goodsInfo.introduction }}</view>
</view>
<!-- 功能卡片 -->
<view class="detail-cell-card detail-card ss-flex-col">
<detail-cell-sku :sku="state.selectedSku" @tap="state.showSelectSku = true" />
</view>
<!-- 规格与数量弹框 -->
<s-select-seckill-sku
v-model="state.goodsInfo"
:show="state.showSelectSku"
:single-limit-count="activity.singleLimitCount"
@buy="onBuy"
@change="onSkuChange"
@close="state.showSelectSku = false"
/>
</view>
<!-- 评价 -->
<detail-comment-card class="detail-comment-selector" :goodsId="state.goodsInfo.id" />
<!-- 详情 -->
<detail-content-card class="detail-content-selector" :content="state.goodsInfo.description" />
<!-- 详情tabbar -->
<detail-tabbar v-model="state.goodsInfo">
<view class="buy-box ss-flex ss-col-center ss-p-r-20">
<button
class="ss-reset-button origin-price-btn ss-flex-col"
v-if="state.goodsInfo.marketPrice"
@tap="sheep.$router.go('/pages/goods/index', { id: state.goodsInfo.id })"
>
<view>
<view class="btn-price">{{ fen2yuan(state.goodsInfo.marketPrice) }}</view>
<view>原价购买</view>
</view>
</button>
<button
class="ss-reset-button btn-box ss-flex-col"
@tap="state.showSelectSku = true"
:class="
state.goodsInfo.stock != 0
? 'check-btn-box'
: 'disabled-btn-box'
"
:disabled="state.goodsInfo.stock === 0"
>
<view class="price-box ss-flex">
<image
:src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
style="width: 36rpx;height: 36rpx;margin: 0 4rpx;"
></image>
<text class="point-text ss-m-r-16">
{{ getShowPrice.point }}
{{ !getShowPrice.price || getShowPrice.price === 0 ? '' : `+¥${getShowPrice.price}` }}
</text>
</view>
<view v-if="state.goodsInfo.stock === 0">已售罄</view>
<view v-else>立即兑换</view>
</button>
</view>
</detail-tabbar>
</block>
</s-layout>
</template>
<script setup>
import { computed, reactive, ref, unref } from 'vue';
import { onLoad, onPageScroll } from '@dcloudio/uni-app';
import sheep from '@/sheep';
import { isEmpty } from 'lodash-es';
import { fen2yuan, formatExchange, formatGoodsSwiper } from '@/sheep/hooks/useGoods';
import detailNavbar from './components/detail/detail-navbar.vue';
import detailCellSku from './components/detail/detail-cell-sku.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 SpuApi from '@/sheep/api/product/spu';
import { PromotionActivityTypeEnum } from '@/sheep/util/const';
import PointApi from '@/sheep/api/promotion/point';
const headerBg = sheep.$url.css('/static/img/shop/goods/score-bg.png');
const btnBg = sheep.$url.css('/static/img/shop/goods/seckill-btn.png');
const disabledBtnBg = sheep.$url.css('/static/img/shop/goods/activity-btn-disabled.png');
const seckillBg = sheep.$url.css('/static/img/shop/goods/seckill-tip-bg.png');
const grouponBg = sheep.$url.css('/static/img/shop/goods/groupon-tip-bg.png');
onPageScroll(() => {
});
const state = reactive({
skeletonLoading: true,
goodsInfo: {},
showSelectSku: false,
goodsSwiper: [],
selectedSku: {},
showModel: false,
total: 0,
price: '',
});
//
function onSkuChange(e) {
state.selectedSku = e;
}
//
function onBuy(sku) {
sheep.$router.go('/pages/order/confirm', {
data: JSON.stringify({
order_type: 'goods',
buy_type: 'point',
pointActivityId: activity.value.id,
items: [
{
skuId: sku.id,
count: sku.count,
},
],
}),
});
}
//
// TODO puhui999: fix
const shareInfo = computed(() => {
if (isEmpty(unref(activity))) return {};
return sheep.$platform.share.getShareInfo(
{
title: activity.value.name,
image: sheep.$url.cdn(state.goodsInfo.picUrl),
params: {
page: '4',
query: activity.value.id,
},
},
{
type: 'goods', //
title: activity.value.name, //
image: sheep.$url.cdn(state.goodsInfo.picUrl), //
price: state.goodsInfo.price, //
marketPrice: state.goodsInfo.marketPrice, //
},
);
});
const activity = ref();
const getShowPrice = computed(() => {
if (!isEmpty(state.selectedSku)) {
const sku = state.selectedSku;
return {
point: sku.point,
price: !sku.pointPrice ? '' : fen2yuan(sku.pointPrice),
};
}
return {
point: activity.value.point,
price: !activity.value.price ? '' : fen2yuan(activity.value.price),
};
});
const getShowPriceText = computed(() => {
let priceText = `${fen2yuan(state.goodsInfo.price)}`;
if (!isEmpty(state.selectedSku)) {
const sku = state.selectedSku;
priceText = `${sku.point}${!sku.pointPrice ? '' : `+¥${fen2yuan(sku.pointPrice)}`}`;
}
return priceText;
});
//
const getActivity = async (id) => {
const { data } = await PointApi.getPointActivity(id);
activity.value = data;
//
await getSpu(data.spuId);
};
//
const getSpu = async (id) => {
const { data } = await SpuApi.getSpuDetail(id);
data.activity_type = PromotionActivityTypeEnum.POINT.type;
state.goodsInfo = data;
state.goodsInfo.stock = Math.min(data.stock, activity.value.stock);
//
state.goodsSwiper = formatGoodsSwiper(state.goodsInfo.sliderPicUrls);
// 使
data.skus.forEach((sku) => {
const product = activity.value.products.find((product) => product.skuId === sku.id);
if (product) {
sku.point = product.point;
sku.pointPrice = product.price;
sku.stock = Math.min(sku.stock, product.stock);
//
sku.limitCount = product.count;
} else {
//
sku.stock = 0;
}
});
state.skeletonLoading = false;
};
onLoad((options) => {
//
if (!options.id) {
state.goodsInfo = null;
return;
}
//
getActivity(options.id);
});
</script>
<style lang="scss" scoped>
.disabled-btn-box[disabled] {
background-color: transparent;
}
.detail-card {
background-color: $white;
margin: 14rpx 20rpx;
border-radius: 10rpx;
overflow: hidden;
}
//
.title-card {
width: 710rpx;
box-sizing: border-box;
background-size: 100% 100%;
border-radius: 10rpx;
background-image: v-bind(headerBg);
background-repeat: no-repeat;
.price-box {
.point-img {
width: 36rpx;
height: 36rpx;
margin: 0 4rpx;
}
.point-text {
font-size: 42rpx;
font-weight: 500;
color: #ff3000;
line-height: 36rpx;
font-family: OPPOSANS;
}
.price-text {
font-size: 42rpx;
font-weight: 500;
color: #ff3000;
line-height: 36rpx;
font-family: OPPOSANS;
}
}
.origin-price-text {
font-size: 26rpx;
font-weight: 400;
text-decoration: line-through;
color: $gray-c;
font-family: OPPOSANS;
}
.sales-text {
font-size: 26rpx;
font-weight: 500;
color: $gray-c;
}
.discounts-box {
.discounts-tag {
padding: 4rpx 10rpx;
font-size: 24rpx;
font-weight: 500;
border-radius: 4rpx;
color: var(--ui-BG-Main);
// background: rgba(#2aae67, 0.05);
background: var(--ui-BG-Main-tag);
}
.discounts-title {
font-size: 24rpx;
font-weight: 500;
color: var(--ui-BG-Main);
line-height: normal;
}
.cicon-forward {
color: var(--ui-BG-Main);
font-size: 24rpx;
line-height: normal;
margin-top: 4rpx;
}
}
.title-text {
font-size: 30rpx;
font-weight: bold;
line-height: 42rpx;
}
.subtitle-text {
font-size: 26rpx;
font-weight: 400;
color: $dark-9;
line-height: 42rpx;
}
}
//
.buy-box {
.check-btn-box {
width: 248rpx;
height: 80rpx;
font-size: 24rpx;
font-weight: 600;
margin-left: -36rpx;
background-image: v-bind(btnBg);
background-repeat: no-repeat;
background-size: 100% 100%;
color: #ffffff;
line-height: normal;
border-radius: 0px 40rpx 40rpx 0px;
}
.disabled-btn-box {
width: 248rpx;
height: 80rpx;
font-size: 24rpx;
font-weight: 600;
margin-left: -36rpx;
background-image: v-bind(disabledBtnBg);
background-repeat: no-repeat;
background-size: 100% 100%;
color: #999999;
line-height: normal;
border-radius: 0px 40rpx 40rpx 0px;
}
.btn-price {
font-family: OPPOSANS;
&::before {
content: '¥';
}
}
.origin-price-btn {
width: 236rpx;
height: 80rpx;
background: rgba(#ff5651, 0.1);
color: #ff6000;
border-radius: 40rpx 0px 0px 40rpx;
line-height: normal;
font-size: 24rpx;
font-weight: 500;
.no-original {
font-size: 28rpx;
}
.btn-title {
font-size: 28rpx;
}
}
}
//
.seckill-box {
background: v-bind(seckillBg) no-repeat;
background-size: 100% 100%;
}
.groupon-box {
background: v-bind(grouponBg) no-repeat;
background-size: 100% 100%;
}
//
.activity-box {
width: 100%;
height: 80rpx;
box-sizing: border-box;
margin-bottom: 10rpx;
.activity-title {
font-size: 26rpx;
font-weight: 500;
color: #ffffff;
line-height: 42rpx;
.activity-icon {
width: 38rpx;
height: 38rpx;
}
}
.activity-go {
width: 70rpx;
height: 32rpx;
background: #ffffff;
border-radius: 16rpx;
font-weight: 500;
color: #ff6000;
font-size: 24rpx;
line-height: normal;
}
}
.model-box {
.title {
font-size: 36rpx;
font-weight: bold;
color: #333333;
}
.subtitle {
font-size: 26rpx;
font-weight: 500;
color: #333333;
}
}
</style>

389
pages/goods/sales.vue Normal file
View File

@ -0,0 +1,389 @@
<template>
<s-layout navbar="normal" :leftWidth="0" :rightWidth="0" >
<!-- 筛选 -->
<!-- <su-sticky bgColor="#fff">
<view class="ss-flex">
<view class="ss-flex-1">
<su-tabs :list="state.tabList" :scrollable="false" @change="onTabsChange"
:current="state.currentTab" />
</view>
<view class="list-icon" @tap="state.iconStatus = !state.iconStatus">
<text v-if="state.iconStatus" class="sicon-goods-list" />
<text v-else class="sicon-goods-card" />
</view>
</view>
</su-sticky> -->
<view class="title">
促销商品
</view>
<!-- 弹窗 -->
<su-popup :show="state.showFilter" type="top" round="10" :space="sys_navBar + 38" backgroundColor="#F6F6F6"
:zIndex="10" @close="state.showFilter = false">
<view class="filter-list-box">
<view class="filter-item" v-for="(item, index) in state.tabList[state.currentTab].list"
:key="item.value" :class="[{ 'filter-item-active': index === state.curFilter }]"
@tap="onFilterItem(index)">
{{ item.label }}
</view>
</view>
</su-popup>
<!-- 情况一单列布局 -->
<view class="goods-list ss-m-t-20">
<view class="ss-p-l-20 ss-p-r-20 ss-m-b-20" v-for="item in state.pagination.list" :key="item.id">
<s-goods-column class="" size="lg" :data="item" :topRadius="10" :bottomRadius="10"
@click="sheep.$router.go('/pages/goods/index', { id: item.id })" />
</view>
</view>
<!-- 情况二双列布局 -->
<!-- <view v-if="!state.iconStatus && state.pagination.total > 0"
class="ss-flex ss-flex-wrap ss-p-x-20 ss-m-t-20 ss-col-top">
<view class="goods-list-box">
<view class="left-list" v-for="item in state.leftGoodsList" :key="item.id">
<s-goods-column class="goods-md-box" size="md" :data="item" :topRadius="10" :bottomRadius="10"
@click="sheep.$router.go('/pages/goods/index', { id: item.id })"
@getHeight="mountMasonry($event, 'left')">
<template v-slot:cart>
<button class="ss-reset-button cart-btn" />
</template>
</s-goods-column>
</view>
</view>
<view class="goods-list-box">
<view class="right-list" v-for="item in state.rightGoodsList" :key="item.id">
<s-goods-column class="goods-md-box" size="md" :topRadius="10" :bottomRadius="10" :data="item"
@click="sheep.$router.go('/pages/goods/index', { id: item.id })"
@getHeight="mountMasonry($event, 'right')">
<template v-slot:cart>
<button class="ss-reset-button cart-btn" />
</template>
</s-goods-column>
</view>
</view>
</view> -->
<uni-load-more v-if="state.pagination.total > 0" :status="state.loadStatus" :content-text="{
contentdown: '上拉加载更多',
}" @tap="loadMore" />
<s-empty v-if="state.pagination.total === 0" icon="/static/soldout-empty.png" text="暂无商品" />
</s-layout>
</template>
<script setup>
import {
reactive
} from 'vue';
import {
onLoad,
onReachBottom
} from '@dcloudio/uni-app';
import sheep from '@/sheep';
import _ from 'lodash';
import {
resetPagination
} from '@/sheep/util';
import SpuApi from '@/sheep/api/product/spu';
const sys_navBar = sheep.$platform.navbar;
const emits = defineEmits(['close', 'change']);
const state = reactive({
pagination: {
list: [],
total: 0,
pageNo: 1,
pageSize: 6,
},
currentSort: undefined,
currentOrder: undefined,
currentTab: 0, // tab
curFilter: 0, // list
showFilter: false,
iconStatus: false, // true - false -
keyword: '',
categoryId: 0,
tabList: [{
name: '综合推荐',
list: [{
label: '综合推荐',
},
{
label: '价格升序',
sort: 'price',
order: true,
},
{
label: '价格降序',
sort: 'price',
order: false,
},
],
},
{
name: '销量',
sort: 'salesCount',
order: false,
},
{
name: '新品优先',
value: 'createTime',
order: false,
},
],
loadStatus: '',
leftGoodsList: [], // -
rightGoodsList: [], // -
});
//
let count = 0;
let leftHeight = 0;
let rightHeight = 0;
// leftGoodsList + rightGoodsList
function mountMasonry(height = 0, where = 'left') {
if (!state.pagination.list[count]) {
return;
}
if (where === 'left') {
leftHeight += height;
} else {
rightHeight += height;
}
if (leftHeight <= rightHeight) {
state.leftGoodsList.push(state.pagination.list[count]);
} else {
state.rightGoodsList.push(state.pagination.list[count]);
}
count++;
}
//
function emptyList() {
resetPagination(state.pagination);
state.leftGoodsList = [];
state.rightGoodsList = [];
count = 0;
leftHeight = 0;
rightHeight = 0;
}
//
function onSearch(e) {
state.keyword = e;
emptyList();
getList(state.currentSort, state.currentOrder);
}
//
function onTabsChange(e) {
//
if (state.tabList[e.index].list) {
state.currentTab = e.index;
state.showFilter = !state.showFilter;
return;
}
state.showFilter = false;
// tab
if (e.index === state.currentTab) {
return;
}
state.currentTab = e.index;
state.currentSort = e.sort;
state.currentOrder = e.order;
emptyList();
getList(e.sort, e.order);
}
// tab list
const onFilterItem = (val) => {
//
// tabList[0] list
if (
state.currentSort === state.tabList[0].list[val].sort &&
state.currentOrder === state.tabList[0].list[val].order
) {
state.showFilter = false;
return;
}
state.showFilter = false;
//
state.curFilter = val;
state.tabList[0].name = state.tabList[0].list[val].label;
state.currentSort = state.tabList[0].list[val].sort;
state.currentOrder = state.tabList[0].list[val].order;
// +
emptyList();
getList();
};
async function getList() {
state.loadStatus = 'loading';
const {
code,
data
} = await SpuApi.getSpusales({
pageNo: state.pagination.pageNo,
pageSize: state.pagination.pageSize,
sortField: state.currentSort,
sortAsc: state.currentOrder,
categoryId: state.categoryId,
keyword: state.keyword,
recommendBenefit:1
});
if (code !== 0) {
return;
}
state.pagination.list = _.concat(state.pagination.list, data.list);
state.pagination.total = data.total;
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
mountMasonry();
}
//
function loadMore() {
if (state.loadStatus === 'noMore') {
return;
}
state.pagination.pageNo++;
getList(state.currentSort, state.currentOrder);
}
//
const getSpu = async (id) => {
const data = await SpuApi.getSpusales({recommendBenefit:1});
console.log(data, "我要留了")
};
onLoad((options) => {
state.categoryId = options.categoryId;
state.keyword = options.keyword;
getList(state.currentSort, state.currentOrder);
});
//
onReachBottom(() => {
loadMore();
});
</script>
<style lang="scss" scoped>
.title{
text-align: center;
padding: 10px 0;
position: relative;
&:after {
position: absolute;
content:'';
top: 50%;
left: 98px;
width: 100px;
height:2px;
background:#dadada;
transform: translateX(-50%);
}
&:before {
position: absolute;
content:'';
height:2px;
top: 50%;
right: 0;
width: 100px;
background:#dadada;
transform: translateX(-50%);
}
}
.goods-list-box {
width: 50%;
box-sizing: border-box;
.left-list {
margin-right: 10rpx;
margin-bottom: 20rpx;
}
.right-list {
margin-left: 10rpx;
margin-bottom: 20rpx;
}
}
.goods-box {
&:nth-last-of-type(1) {
margin-bottom: 0 !important;
}
&:nth-child(2n) {
margin-right: 0;
}
}
.list-icon {
width: 80rpx;
.sicon-goods-card {
font-size: 40rpx;
}
.sicon-goods-list {
font-size: 40rpx;
}
}
.goods-card {
margin-left: 20rpx;
}
.list-filter-tabs {
background-color: #fff;
}
.filter-list-box {
padding: 28rpx 52rpx;
.filter-item {
font-size: 28rpx;
font-weight: 500;
color: #333333;
line-height: normal;
margin-bottom: 24rpx;
&:nth-last-child(1) {
margin-bottom: 0;
}
}
.filter-item-active {
color: var(--ui-BG-Main);
}
}
.tab-item {
height: 50px;
position: relative;
z-index: 11;
.tab-title {
font-size: 30rpx;
}
.cur-tab-title {
font-weight: $font-weight-bold;
}
.tab-line {
width: 60rpx;
height: 6rpx;
border-radius: 6rpx;
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 10rpx;
background-color: var(--ui-BG-Main);
z-index: 12;
}
}
</style>

File diff suppressed because one or more lines are too long

View File

@ -24,12 +24,12 @@
:style="[{ height: pageHeight + 'px' }]"
v-if="state.categoryList?.length"
>
<image
<!-- <image
v-if="state.categoryList[state.activeMenu].picUrl"
class="banner-img"
:src="sheep.$url.cdn(state.categoryList[state.activeMenu].picUrl)"
mode="widthFix"
/>
/> -->
<first-one v-if="state.style === 'first_one'" :pagination="state.pagination" />
<first-two v-if="state.style === 'first_two'" :pagination="state.pagination" />
<second-one

View File

@ -3,7 +3,6 @@
<s-layout
:title="state.name"
navbar="custom"
tabbar="/pages/index/page"
:bgStyle="state.page"
:navbarStyle="state.navigationBar"
onShareAppMessage
@ -27,7 +26,7 @@
page: {},
});
onLoad(async (options) => {
let id = options.id;
let id = options.id
// #ifdef MP
//

View File

@ -1,27 +1,24 @@
<!-- 个人中心支持装修 -->
<template>
<s-layout
title=" "
tabbar="/pages/index/user"
navbar="normal"
:bgStyle="template.page"
:navbarStyle="template.navigationBar"
onShareAppMessage
>
<image class="seckill" src="@/static/images/seckill-bg.png"></image>
<s-block
v-for="(item, index) in template.components"
:key="index"
:styles="item.property.style"
>
<s-layout title="个人中心" tabbar="/pages/index/user" navbar="normal" :bgStyle="template.page"
:navbarStyle="template.navigationBar" onShareAppMessage>
<image class="seckill" src="@/static/images/seckilbg.png"></image>
<s-block class="" v-for="(item, index) in template.components" :key="index" :styles="item.property.style">
<s-block-item :type="item.id" :data="item.property" :styles="item.property.style" />
</s-block>
</s-layout>
</template>
<script setup>
import { computed } from 'vue';
import { onShow, onPageScroll, onPullDownRefresh } from '@dcloudio/uni-app';
import {
computed
} from 'vue';
import {
onShow,
onPageScroll,
onPullDownRefresh
} from '@dcloudio/uni-app';
import sheep from '@/sheep';
// tabBar
@ -45,10 +42,23 @@
</script>
<style>
.new-main{
}
.seckill1 {
position: absolute;
top: 117px;
z-index: 22;
left: 50%;
transform: translateX(-50%);
width: 94%;
}
.seckill {
width: 100%;
position: absolute;
}
view {
position: relative;
}

390
pages/integration/index.vue Normal file
View File

@ -0,0 +1,390 @@
<template>
<s-layout navbar="normal" :leftWidth="0" :rightWidth="0" >
<!-- 筛选 -->
<!-- <su-sticky bgColor="#fff">
<view class="ss-flex">
<view class="ss-flex-1">
<su-tabs :list="state.tabList" :scrollable="false" @change="onTabsChange"
:current="state.currentTab" />
</view>
<view class="list-icon" @tap="state.iconStatus = !state.iconStatus">
<text v-if="state.iconStatus" class="sicon-goods-list" />
<text v-else class="sicon-goods-card" />
</view>
</view>
</su-sticky> -->
<view class="title">
积分商品
</view>
<!-- 弹窗 -->
<su-popup :show="state.showFilter" type="top" round="10" :space="sys_navBar + 38" backgroundColor="#F6F6F6"
:zIndex="10" @close="state.showFilter = false">
<view class="filter-list-box">
<view class="filter-item" v-for="(item, index) in state.tabList[state.currentTab].list"
:key="item.value" :class="[{ 'filter-item-active': index === state.curFilter }]"
@tap="onFilterItem(index)">
{{ item.label }}
</view>
</view>
</su-popup>
<!-- 情况一单列布局 -->
<view class="goods-list ss-m-t-20">
<view class="ss-p-l-20 ss-p-r-20 ss-m-b-20" v-for="item in state.pagination.list" :key="item.id">
<dfff class="" size="lg" :data="item" :topRadius="10" :bottomRadius="10"
@click="sheep.$router.go('/pages/goods/index', { id: item.id })" />
</view>
</view>
<!-- 情况二双列布局 -->
<!-- <view v-if="!state.iconStatus && state.pagination.total > 0"
class="ss-flex ss-flex-wrap ss-p-x-20 ss-m-t-20 ss-col-top">
<view class="goods-list-box">
<view class="left-list" v-for="item in state.leftGoodsList" :key="item.id">
<s-goods-column class="goods-md-box" size="md" :data="item" :topRadius="10" :bottomRadius="10"
@click="sheep.$router.go('/pages/goods/index', { id: item.id })"
@getHeight="mountMasonry($event, 'left')">
<template v-slot:cart>
<button class="ss-reset-button cart-btn" />
</template>
</s-goods-column>
</view>
</view>
<view class="goods-list-box">
<view class="right-list" v-for="item in state.rightGoodsList" :key="item.id">
<s-goods-column class="goods-md-box" size="md" :topRadius="10" :bottomRadius="10" :data="item"
@click="sheep.$router.go('/pages/goods/index', { id: item.id })"
@getHeight="mountMasonry($event, 'right')">
<template v-slot:cart>
<button class="ss-reset-button cart-btn" />
</template>
</s-goods-column>
</view>
</view>
</view> -->
<uni-load-more v-if="state.pagination.total > 0" :status="state.loadStatus" :content-text="{
contentdown: '上拉加载更多',
}" @tap="loadMore" />
<s-empty v-if="state.pagination.total === 0" icon="/static/soldout-empty.png" text="暂无商品" />
</s-layout>
</template>
<script setup>
import {
reactive
} from 'vue';
import {
onLoad,
onReachBottom
} from '@dcloudio/uni-app';
import sheep from '@/sheep';
import _ from 'lodash';
import {
resetPagination
} from '@/sheep/util';
import SpuApi from '@/sheep/api/product/spu';
import dfff from '@/sheep/components/s-goods-column/s-goods-column-jf';
const sys_navBar = sheep.$platform.navbar;
const emits = defineEmits(['close', 'change']);
const state = reactive({
pagination: {
list: [],
total: 0,
pageNo: 1,
pageSize: 6,
},
currentSort: undefined,
currentOrder: undefined,
currentTab: 0, // tab
curFilter: 0, // list
showFilter: false,
iconStatus: false, // true - false -
keyword: '',
categoryId: 0,
tabList: [{
name: '综合推荐',
list: [{
label: '综合推荐',
},
{
label: '价格升序',
sort: 'price',
order: true,
},
{
label: '价格降序',
sort: 'price',
order: false,
},
],
},
{
name: '销量',
sort: 'salesCount',
order: false,
},
{
name: '新品优先',
value: 'createTime',
order: false,
},
],
loadStatus: '',
leftGoodsList: [], // -
rightGoodsList: [], // -
});
//
let count = 0;
let leftHeight = 0;
let rightHeight = 0;
// leftGoodsList + rightGoodsList
function mountMasonry(height = 0, where = 'left') {
if (!state.pagination.list[count]) {
return;
}
if (where === 'left') {
leftHeight += height;
} else {
rightHeight += height;
}
if (leftHeight <= rightHeight) {
state.leftGoodsList.push(state.pagination.list[count]);
} else {
state.rightGoodsList.push(state.pagination.list[count]);
}
count++;
}
//
function emptyList() {
resetPagination(state.pagination);
state.leftGoodsList = [];
state.rightGoodsList = [];
count = 0;
leftHeight = 0;
rightHeight = 0;
}
//
function onSearch(e) {
state.keyword = e;
emptyList();
getList(state.currentSort, state.currentOrder);
}
//
function onTabsChange(e) {
//
if (state.tabList[e.index].list) {
state.currentTab = e.index;
state.showFilter = !state.showFilter;
return;
}
state.showFilter = false;
// tab
if (e.index === state.currentTab) {
return;
}
state.currentTab = e.index;
state.currentSort = e.sort;
state.currentOrder = e.order;
emptyList();
getList(e.sort, e.order);
}
// tab list
const onFilterItem = (val) => {
//
// tabList[0] list
if (
state.currentSort === state.tabList[0].list[val].sort &&
state.currentOrder === state.tabList[0].list[val].order
) {
state.showFilter = false;
return;
}
state.showFilter = false;
//
state.curFilter = val;
state.tabList[0].name = state.tabList[0].list[val].label;
state.currentSort = state.tabList[0].list[val].sort;
state.currentOrder = state.tabList[0].list[val].order;
// +
emptyList();
getList();
};
async function getList() {
state.loadStatus = 'loading';
const {
code,
data
} = await SpuApi.getSpusales({
pageNo: state.pagination.pageNo,
pageSize: state.pagination.pageSize,
sortField: state.currentSort,
sortAsc: state.currentOrder,
categoryId: state.categoryId,
keyword: state.keyword,
recommendBenefit:1
});
if (code !== 0) {
return;
}
state.pagination.list = _.concat(state.pagination.list, data.list);
state.pagination.total = data.total;
state.loadStatus = state.pagination.list.length < state.pagination.total ? 'more' : 'noMore';
mountMasonry();
}
//
function loadMore() {
if (state.loadStatus === 'noMore') {
return;
}
state.pagination.pageNo++;
getList(state.currentSort, state.currentOrder);
}
//
const getSpu = async (id) => {
const data = await SpuApi.getSpusales({recommendBenefit:1});
console.log(data, "我要留了")
};
onLoad((options) => {
state.categoryId = options.categoryId;
state.keyword = options.keyword;
getList(state.currentSort, state.currentOrder);
});
//
onReachBottom(() => {
loadMore();
});
</script>
<style lang="scss" scoped>
.title{
text-align: center;
padding: 10px 0;
position: relative;
&:after {
position: absolute;
content:'';
top: 50%;
left: 98px;
width: 100px;
height:2px;
background:#dadada;
transform: translateX(-50%);
}
&:before {
position: absolute;
content:'';
height:2px;
top: 50%;
right: 0;
width: 100px;
background:#dadada;
transform: translateX(-50%);
}
}
.goods-list-box {
width: 50%;
box-sizing: border-box;
.left-list {
margin-right: 10rpx;
margin-bottom: 20rpx;
}
.right-list {
margin-left: 10rpx;
margin-bottom: 20rpx;
}
}
.goods-box {
&:nth-last-of-type(1) {
margin-bottom: 0 !important;
}
&:nth-child(2n) {
margin-right: 0;
}
}
.list-icon {
width: 80rpx;
.sicon-goods-card {
font-size: 40rpx;
}
.sicon-goods-list {
font-size: 40rpx;
}
}
.goods-card {
margin-left: 20rpx;
}
.list-filter-tabs {
background-color: #fff;
}
.filter-list-box {
padding: 28rpx 52rpx;
.filter-item {
font-size: 28rpx;
font-weight: 500;
color: #333333;
line-height: normal;
margin-bottom: 24rpx;
&:nth-last-child(1) {
margin-bottom: 0;
}
}
.filter-item-active {
color: var(--ui-BG-Main);
}
}
.tab-item {
height: 50px;
position: relative;
z-index: 11;
.tab-title {
font-size: 30rpx;
}
.cur-tab-title {
font-weight: $font-weight-bold;
}
.tab-line {
width: 60rpx;
height: 6rpx;
border-radius: 6rpx;
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 10rpx;
background-color: var(--ui-BG-Main);
z-index: 12;
}
}
</style>

View File

@ -42,7 +42,7 @@
</view>
<view
class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderInfo.type === 0"
v-if="state.orderInfo.type === 0 && state.orderInfo.pointsStatus === 1"
>
<view class="item-title">积分抵扣</view>
<view class="ss-flex ss-col-center">
@ -52,7 +52,7 @@
class="score-img"
/>
<text class="item-value ss-m-r-24">
{{ state.pointStatus ? state.orderInfo.totalPoint - state.orderInfo.usePoint : (state.orderInfo.totalPoint || 0) }}
{{ state.pointStatus ? state.orderInfo.totalPoint - state.orderInfo.usedPoint : (state.orderInfo.totalPoint || 0) }}
</text>
<checkbox-group @change="changeIntegral">
<checkbox :checked='state.pointStatus' :disabled="!state.orderInfo.totalPoint || state.orderInfo.totalPoint <= 0" />

View File

@ -0,0 +1,827 @@
<template>
<s-layout title="预约" :bgStyle="{ color: '#fff' }">
<view class="container">
<view class="doctor-list">
<view class="doctor-cards">
<image class="doctor-avatars" :src="brandList.list[selectedClinicIndex].picUrl"
mode="aspectFill"></image><br /><br />
<view class="brandr-info">
<text class="doctor-names">
<text class="ygcontent">医馆地址</text>
{{ brandList.list[selectedClinicIndex].address }}</text><br /><br />
<!-- <div v-html='brandList.list[selectedClinicIndex].depict'></div> -->
<rich-text class="doctor-specialtys" :nodes="brandList.list[selectedClinicIndex].depict"></rich-text>
</view>
</view>
</view>
<view class="clinic-select">
<text class="clinic-select-label">医馆选择</text>
<picker mode="selector" :range="brandNameList" @change="onClinicChange">
<view class="clinic-select-value">
<text>{{ brandList.list[selectedClinicIndex].name}}</text>
</view>
</picker>
</view>
<view class="clinic-select">
<text class="clinic-select-label">预约类型</text>
<picker mode="selector" :range="typenameList" @change="ontype">
<view class="clinic-select-value">
<text>{{ typeList[selecttypeIndex].label}}</text>
</view>
</picker>
</view>
<!-- <text class="clinic-select-label">套餐选择</text><br>
<image class="doctor-avatar" src="/static/avatar-doctor.png" mode="aspectFill"></image> -->
<!-- <view class="date-card">
<view class="weekdays">
<text v-for="(day, index) in weekdays" :key="index" :class="['weekday', index === selectedDayIndex ? 'active' : '']"
@click="selectDay(index)">{{ day }}</text>
</view>
<swiper class="date-swiper" :current="selectedDayIndex" @change="handleSwiperChange">
<swiper-item v-for="(date, index) in dateList" :key="index">
<view class="date-item" :class="index === selectedDayIndex ? 'active' : ''">
<text class="date">{{ formatDate(date.date) }}</text>
</view>
</swiper-item>
</swiper>
</view> -->
<radio-group>
<view class="date-list">
<view v-for="(item, index) in dateList" :key="index" @click="selectDate(index)">
<view class="date-item" v-if="addDate==item.addDate" style="background-color: #ff5541;">
<text class="date" style="color: #FFFFFF;">{{ item.formattedDate }}</text>
<text class="weekday" style="color: #FFFFFF;">{{ item.weekday }}</text>
</view>
<view class="date-item" v-if="addDate!=item.addDate">
<text class="date">{{ item.formattedDate }}</text>
<text class="weekday">{{ item.weekday }}</text>
</view>
</view>
</view>
</radio-group>
<!-- <view @click="showTime = true"><text v-if="goTime" style="color: #000;">{{goTime }}</text><text v-else>请选择返程时间</text></view> -->
<!-- //showTime -->
<!-- <pickerTime :startH="8" :lateH="19" :step="32" v-if="showTime" @close="showTime=false" @chooseTime="bindTime"></pickerTime> -->
<radio-group>
<view class="doctor-list">
<!-- {{techList}} -->
<view class="doctor-card" v-for="(item, index) in techList" :key="index">
<view class="doctor-info">
<image class="doctor-avatar" :src="'https://sfyjk.com/api'+item.photo" mode="aspectFill">
</image>
<text class="doctor-name">{{ item.technicianName }}</text>
<text class="doctor-name" style="float: right;margin-right: 20px;">{{item.typeName}}</text>
<!-- <text class="doctor-specialty" v-if="item.content">介绍: {{item.content.substr(0, 20)}}...</text> -->
</view>
<radio style="float: right;" :value="item.id" @click="onradio(item)" :checked="index==0">
</radio>
<div v-if="techid == item.id">
<view class="info-title">服务范围</view>
<rich-text style="white-space: pre-wrap;" :nodes="item.serviceScope"></rich-text>
<view class="info-title">介绍</view>
<rich-text style="white-space: pre-wrap;" :nodes="item.content"></rich-text>
</div>
</view>
</view>
</radio-group>
<radio-group>
<view class="date-list">
<view v-for="(item, index) in serviceTime" :key="index" @click="selecthsstr(index)">
<view class="date-itemstr" v-if="hsstr==item.str" style="background-color: #ff5541;">
<text class="weekday">{{ item.str }}</text>
</view>
<view v-if="item.ym==='true'">
<view class="date-itemym" v-if="hsstr!=item.str">
<text class="weekdayym">约满</text><br />
<text class="weekday">{{ item.str }}</text>
</view>
</view>
<view v-if="item.ym==='false'">
<view class="date-itemstr" v-if="hsstr!=item.str">
<text class="weekday">{{ item.str }}</text>
</view>
</view>
</view>
</view>
</radio-group>
<view class="footer">
<button class="appointment-btn" @click="handleSubmit">立即预约</button>
</view>
</view>
</s-layout>
</template>
<script>
import request from '@/sheep/request';
import {
baseUrl,
apiPath
} from '@/sheep/config';
import {
computed
} from 'vue';
import sheep from '@/sheep';
import {
showShareModal,
showAuthModal
} from '@/sheep/hooks/useModal';
// import pickerTime from "@/pages/commission/pickerTime.vue"
//
export default {
// components: {
// pickerTime
// },
data() {
return {
isLogin: null,
memberId: null,
// showTime: false,
serviceTime: [],
sjd: {},
ym: [],
// starhour: 8,
// starminute: 0,
// endhour: 18,
// endminute: 0,
// timejg: 70,
hsstr: "",
dateList: [],
typeList: [{
dictValue: 0,
dictLabel: "调理预约"
},
{
dictValue: 1,
dictLabel: "教培预约"
}
],
typenameList: [],
addDate: "",
techList: [], //
//
selectedClinicIndex: 0, //
brandList: [{
name: ""
}],
brandNameList: [],
brandId: "",
brandName: "",
selectedDayIndex: 0,
selecttypeIndex: 0,
techid: 0,
type: 0,
};
},
created() {
this.isLogin = computed(() => sheep.$store('user').isLogin);
this.memberId = computed(() => sheep.$store('user').userInfo).value.id
this.brandlists();
this.generateDateList();
this.addDate = this.dateList[0].addDate;
this.gettypeList();
console.log(apiPath, baseUrl, "import.meta.env.SHOPRO_API_PATH")
},
methods: {
onClinicChange(event) {
const selectedClinicIndex = event.detail.value;
this.selectedClinicIndex = selectedClinicIndex;
this.brandName = this.brandList.list[selectedClinicIndex].name
this.brandId = this.brandList.list[selectedClinicIndex].id
console.log("dddddddddddd")
this.technicianList();
},
ontype(event) {
const selecttypeIndex = event.detail.value;
this.selecttypeIndex = selecttypeIndex;
this.typename = this.typeList[selecttypeIndex].dictValue
this.type = this.typeList[selecttypeIndex].dictValue
console.log(this.selecttypeIndex)
this.technicianList();
},
//
brandlists() {
request({
url: `${baseUrl}${apiPath}/h5/brand/list`,
method: 'GET',
custom: {
showLoading: false,
},
}).then((res) => {
this.brandList = res.data
console.log(this.brandList,"this.brandList")
for (var i = 0; i < this.brandList.list.length; i++) {
// this.brandList[i].depict=(this.brandList[i].depict).replace(/\<img/gi, '<img style="max-width:100%;height:auto" ')
this.brandNameList.push(this.brandList.list[i].name)
}
this.brandId = this.brandList[0].id
this.technicianList();
});
// uni.request({
// url: `${baseUrl}/api/h5/brand/list`,
// success: (res) => {
// this.brandList = res.data
// for (var i = 0; i < this.brandList.length; i++) {
// // this.brandList[i].depict=(this.brandList[i].depict).replace(/\<img/gi, '<img style="max-width:100%;height:auto" ')
// this.brandNameList.push(this.brandList[i].name)
// }
// this.brandId = this.brandList[0].id
// this.technicianList();
// },
// fail: (error) => {
// console.log(error)
// }
// })
},
gettypeList() {
request({
url: `${baseUrl}${apiPath}/h5/reservation/type`,
method: 'GET',
custom: {
showLoading: false,
},
}).then((res) => {
console.log(res,"typeListtypeList")
this.typeList = res.data
// this.typeList.depict=this.typeList.depict.replace(/\<img/gi, '<img style="max-width:100%;float:left; height:auto" ')
for (var i = 0; i < this.typeList.length; i++) {
this.typenameList.push(this.typeList[i].label);
}
console.log(this.typenameList)
});
// uni.request({
// url: `${baseUrl}/api/h5/reservation/type`,
// success: (res) => {
// this.typeList = res.data.data
// // this.typeList.depict=this.typeList.depict.replace(/\<img/gi, '<img style="max-width:100%;float:left; height:auto" ')
// for (var i = 0; i < this.typeList.length; i++) {
// this.typenameList.push(this.typeList[i].dictLabel);
// }
// console.log(this.typenameList)
// },
// fail: (error) => {
// console.log(error)
// }
// })
},
//
technicianList() {
console.log("有没有进来technicianList");
this.techid = null,
this.serviceTime = []
this.hsstr = ""
request({
url: `${baseUrl}${apiPath}/h5/technician/list`,
method: 'GET',
params:{
type: this.type,
// addDate:this.addDate,
brandId: this.brandId
},
custom: {
showLoading: false,
},
}).then((res) => {
console.log(res)
this.techList = res.data.list
console.log(this.techList)
if (this.techList.length > 0) {
this.techid = this.techList[0].id
var item = {
id: this.techid
}
this.onradio(item);
}
console.log(this.techList)
});
// uni.request({
// // url: 'https://sfyjk.com/api/h5/technician/list',
// url: `${baseUrl}/app-api/h5/technician/list`,
// data: {
// type: this.type,
// // addDate:this.addDate,
// brandId: this.brandId
// },
// success: (res) => {
// console.log(res)
// this.techList = res.data.rows
// console.log(this.techList)
// if (this.techList.length > 0) {
// this.techid = this.techList[0].id
// var item = {
// id: this.techid
// }
// this.onradio(item);
// }
// console.log(this.techList)
// },
// fail: (error) => {
// console.log(error)
// }
// })
},
onradio(item) {
this.techid = item.id
this.serviceTime = []
this.hsstr = ""
request({
url: `${baseUrl}${apiPath}/h5/technician/h5xq`,
method: 'GET',
params:{
addDate: this.addDate,
id: this.techid
},
custom: {
showLoading: false,
},
}).then((res) => {
console.log(res);
var serviceTime = JSON.parse(res.data.serviceTime)
console.log(serviceTime,"serviceTimeserviceTimeserviceTime")
if (serviceTime) {
for (let i = 0; i < serviceTime.length; i++) {
console.log(serviceTime[i].end)
console.log(serviceTime[i].start)
console.log(serviceTime[i].ym)
if (serviceTime[i].end && serviceTime[i].start) {
this.sjd = {},
this.sjd.str = serviceTime[i].start.toString() + "-" + serviceTime[
i].end.toString()
this.sjd.ym = serviceTime[i].ym
this.serviceTime.push(this.sjd)
}
}
}
console.log(this.serviceTime,"this.serviceTime")
});
// uni.request({
// // url: 'https://sfyjk.com/api/h5/technician/' + this.techid, //
// url: `${baseUrl}/app-api/h5/technician/h5xq`, //
// data: {
// addDate: this.addDate,
// id: this.techid
// },
// success: (res) => {
// console.log(res);
// var serviceTime = JSON.parse(res.data.data.serviceTime)
// console.log(serviceTime)
// if (serviceTime) {
// for (let i = 0; i < serviceTime.length; i++) {
// console.log(serviceTime[i].endTime)
// console.log(serviceTime[i].startTime)
// console.log(serviceTime[i].ym)
// if (serviceTime[i].endTime && serviceTime[i].startTime) {
// this.sjd = {},
// this.sjd.str = serviceTime[i].startTime.toString() + "-" + serviceTime[
// i].endTime.toString()
// this.sjd.ym = serviceTime[i].ym
// this.serviceTime.push(this.sjd)
// }
// }
// }
// console.log(this.serviceTime)
// },
// fail: (error) => {
// console.log(error)
// }
// })
},
selectDay(index) {
this.selectedDayIndex = index;
},
handleSwiperChange(event) {
this.selectedDayIndex = event.mp.detail.current;
},
formatDate(date) {
const options = {
month: "2-digit",
day: "2-digit"
};
return date.toLocaleDateString("en-US", options);
},
handleSubmit() {
this.memberId = computed(() => sheep.$store('user').userInfo).value.id
if (!this.memberId) {
if (sheep.$platform.name === 'WechatMiniProgram') {
showAuthModal('wechatMiniLogin')
return;
}
showAuthModal('accountLogin')
} else {
this.memberId = computed(() => sheep.$store('user').userInfo).value.id
if (!this.brandId) {
sheep.$helper.toast('请选择医馆')
} else if (!this.techid) {
sheep.$helper.toast('请选择技师')
} else if (!this.addDate) {
sheep.$helper.toast('请选择预约时间')
} else if (!this.hsstr) {
sheep.$helper.toast('请选择预约时间段')
} else if (this.memberId) {
request({
url: `${baseUrl}/app-api/h5/reservation`,
method: 'post',
params: {
type: this.type,
brandId: this.brandId,
technicianId: this.techid,
reAddTime: this.addDate,
hsstr: this.hsstr,
userId: this.memberId,
},
custom: {
showLoading: false,
},
}).then((res) => {
uni.showModal({
title: '预约提示',
content: '预约成功!',
success: function(res) {
if (res.confirm) {
uni.switchTab({
url: '/pages/index/user'
});
} else {
uni.switchTab({
url: '/pages/index/user'
});
}
}
});
});
// uni.request({
// method: "post",
// url: `${baseUrl}/app-api/h5/reservation`,
// data: {
// type: this.type,
// brandId: this.brandId,
// technicianId: this.techid,
// reAddTime: this.addDate,
// hsstr: this.hsstr,
// userId: this.memberId,
// },
// success: (res) => {
// uni.showModal({
// title: '',
// content: '',
// success: function(res) {
// if (res.confirm) {
// uni.switchTab({
// url: '/pages/index/user'
// });
// } else {
// uni.switchTab({
// url: '/pages/index/user'
// });
// }
// }
// });
// },
// fail: (error) => {
// console.log(error)
// }
// })
}
}
console.log("立即预约");
},
generateDateList() {
const weekDays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
const today = new Date();
for (let i = 0; i < 7; i++) {
const date = new Date(today);
date.setDate(date.getDate() + i);
const formattedDate =
// `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;
`${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;
const weekday = weekDays[date.getDay()];
const addDate =
`${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;
this.dateList.push({
date,
formattedDate,
addDate,
weekday
});
}
},
selectDate(index) {
this.addDate = this.dateList[index].addDate
if (this.techid) {
var item = {
id: this.techid
}
this.onradio(item);
}
//
console.log('Selected date:', this.addDate);
},
selecthsstr(index) {
console.log(this.serviceTime[index].str)
console.log(this.serviceTime[index].ym)
if (this.serviceTime[index].ym === "true") {
} else if (this.serviceTime[index].ym === "false") {
this.hsstr = this.serviceTime[index].str
}
//
console.log('this.serviceTimesss:', this.serviceTime[index].ym);
},
},
};
</script>
<style scoped>
.container {
padding: 20px;
}
.clinic-select {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.clinic-select-label {
margin-right: 10px;
color: #333;
}
.clinic-select-value {
display: flex;
align-items: center;
padding: 5px 10px;
border: 1px solid #ff5541;
border-radius: 5px;
background-color: #ffd3c1;
color: #ff5541;
}
.info-title {
margin-top: 20px;
font-size: 15px;
font-weight: bold;
margin-bottom: 10px;
}
.dropdown-icon {
width: 12px;
height: 12px;
margin-left: 5px;
}
.date-card {
display: flex;
flex-direction: column;
}
.weekdays {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.weekday {
/* margin-left: 0%; */
font-size: 5px;
color: #666;
cursor: pointer;
}
.weekdayym {
margin-left: 30%;
font-size: 14px;
color: #666;
cursor: pointer;
}
.weekday.active {
color: #333;
font-weight: bold;
}
.date-swiper {
height: 150px;
}
.date-itemstr {
display: flex;
align-items: center;
justify-content: center;
width: 80px;
height: 50px;
border-radius: 10px;
background-color: #f0f0f0;
margin-right: 15px;
cursor: pointer;
}
.date-itemym {
/* display: flex; */
align-items: center;
justify-content: center;
width: 80px;
height: 50px;
border-radius: 10px;
background-color: #f0898b;
margin-right: 15px;
cursor: pointer;
}
.date-item.active {
background-color: #ff5541;
color: #fff;
}
.date {
font-size: 16px;
color: #333;
}
.doctor-list {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.doctor-card {
/* display: flex; */
align-items: center;
padding: 10px;
width: 400px;
background-color: #ffd3c1;
border: 1px solid #ff5541;
border-radius: 10px;
margin-bottom: 10px;
}
.doctor-cards {
/* display: flex; */
align-items: center;
padding: 10px;
width: 400px;
background-color: #f0f0f0;
/* border: 1px solid #fff; */
border-radius: 10px;
margin-bottom: 10px;
}
.doctor-avatar {
width: 100px;
height: 70px;
border-radius: 50%;
margin-right: 10px;
}
.doctor-avatars {
display: flex;
/* height: 70px; */
/* border-radius: 50%; */
/* margin-right: 10px; */
}
.doctor-info {
display: flex;
flex-grow: 1;
}
.brandr-info {
/* display: flex; */
flex-grow: 1;
}
.doctor-name {
font-size: 20px;
color: #ff5541;
margin-top: 15px;
margin-left: 20px;
/* margin-bottom: 5px; */
}
.doctor-specialty {
font-size: 14px;
color: #ff5541;
}
.doctor-names {
font-size: 14px;
/* color: #ff5541; */
margin-bottom: 5px;
}
.ygcontent {
font-size: 16px;
font-weight: 700;
}
.doctor-specialtys {
/* text-indent: 20px; */
white-space: pre-wrap;
font-size: 14px;
/* color: #ff5541; */
}
.doctor-checkbox {
margin-left: auto;
}
.footer {
display: flex;
justify-content: center;
margin-top: 20px;
}
.appointment-btn {
width: 200px;
height: 40px;
border-radius: 20px;
background-color: #ff5541;
color: #fff;
font-size: 16px;
}
.date-list {
/* width: 100px; */
display: flex;
flex-wrap: wrap;
}
.date-item {
float: left;
margin: 5px;
padding: 5px;
width: 26px;
height: 30px;
border: 1px solid #fff;
cursor: pointer;
display: flex;
background-color: #efefef;
flex-direction: column;
align-items: center;
}
.date-item:hover {
/* background-color: #ff5541; */
}
.date {
font-size: 8px;
}
.weekday {
margin-top: 5px;
font-size: 10px;
color: #666;
}
.radiodate {
display: none;
}
</style>

View File

@ -214,12 +214,12 @@
}
.store-cent-left {
//width: 45%;
flex: 2;
width: 177px;
// flex: 2;
}
.store-img {
flex: 1;
// flex: 1;
width: 120rpx;
height: 120rpx;
border-radius: 6rpx;

309
pages/user/user_vip/dayjs/dayjs.min.js vendored Normal file
View File

@ -0,0 +1,309 @@
! function(t, e) {
"object" == typeof exports && "undefined" != typeof module ? module.exports = e() : "function" == typeof define &&
define.amd ? define(e) : t.dayjs = e()
}(this, function() {
"use strict";
var t = "millisecond",
e = "second",
n = "minute",
r = "hour",
i = "day",
s = "week",
u = "month",
o = "quarter",
a = "year",
h = /^(\d{4})-?(\d{1,2})-?(\d{0,2})[^0-9]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?.?(\d{1,3})?$/,
f = /\[([^\]]+)]|Y{2,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,
c = function(t, e, n) {
var r = String(t);
return !r || r.length >= e ? t : "" + Array(e + 1 - r.length).join(n) + t
},
d = {
s: c,
z: function(t) {
var e = -t.utcOffset(),
n = Math.abs(e),
r = Math.floor(n / 60),
i = n % 60;
return (e <= 0 ? "+" : "-") + c(r, 2, "0") + ":" + c(i, 2, "0")
},
m: function(t, e) {
var n = 12 * (e.year() - t.year()) + (e.month() - t.month()),
r = t.clone().add(n, u),
i = e - r < 0,
s = t.clone().add(n + (i ? -1 : 1), u);
return Number(-(n + (e - r) / (i ? r - s : s - r)) || 0)
},
a: function(t) {
return t < 0 ? Math.ceil(t) || 0 : Math.floor(t)
},
p: function(h) {
return {
M: u,
y: a,
w: s,
d: i,
D: "date",
h: r,
m: n,
s: e,
ms: t,
Q: o
} [h] || String(h || "").toLowerCase().replace(/s$/, "")
},
u: function(t) {
return void 0 === t
}
},
$ = {
name: "en",
weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
months: "January_February_March_April_May_June_July_August_September_October_November_December".split(
"_")
},
l = "en",
m = {};
m[l] = $;
var y = function(t) {
return t instanceof v
},
M = function(t, e, n) {
var r;
if (!t) return l;
if ("string" == typeof t) m[t] && (r = t), e && (m[t] = e, r = t);
else {
var i = t.name;
m[i] = t, r = i
}
return !n && r && (l = r), r || !n && l
},
g = function(t, e) {
if (y(t)) return t.clone();
var n = "object" == typeof e ? e : {};
return n.date = t, n.args = arguments, new v(n)
},
D = d;
D.l = M, D.i = y, D.w = function(t, e) {
return g(t, {
locale: e.$L,
utc: e.$u,
$offset: e.$offset
})
};
var v = function() {
function c(t) {
this.$L = this.$L || M(t.locale, null, !0), this.parse(t)
}
var d = c.prototype;
return d.parse = function(t) {
this.$d = function(t) {
var e = t.date,
n = t.utc;
if (null === e) return new Date(NaN);
if (D.u(e)) return new Date;
if (e instanceof Date) return new Date(e);
if ("string" == typeof e && !/Z$/i.test(e)) {
var r = e.match(h);
if (r) return n ? new Date(Date.UTC(r[1], r[2] - 1, r[3] || 1, r[4] || 0, r[5] || 0,
r[6] || 0, r[7] || 0)) : new Date(r[1], r[2] - 1, r[3] || 1, r[4] || 0,
r[5] || 0, r[6] || 0, r[7] || 0)
}
return new Date(e)
}(t), this.init()
}, d.init = function() {
var t = this.$d;
this.$y = t.getFullYear(), this.$M = t.getMonth(), this.$D = t.getDate(), this.$W = t.getDay(),
this.$H = t.getHours(), this.$m = t.getMinutes(), this.$s = t.getSeconds(), this.$ms = t
.getMilliseconds()
}, d.$utils = function() {
return D
}, d.isValid = function() {
return !("Invalid Date" === this.$d.toString())
}, d.isSame = function(t, e) {
var n = g(t);
return this.startOf(e) <= n && n <= this.endOf(e)
}, d.isAfter = function(t, e) {
return g(t) < this.startOf(e)
}, d.isBefore = function(t, e) {
return this.endOf(e) < g(t)
}, d.$g = function(t, e, n) {
return D.u(t) ? this[e] : this.set(n, t)
}, d.year = function(t) {
return this.$g(t, "$y", a)
}, d.month = function(t) {
return this.$g(t, "$M", u)
}, d.day = function(t) {
return this.$g(t, "$W", i)
}, d.date = function(t) {
return this.$g(t, "$D", "date")
}, d.hour = function(t) {
return this.$g(t, "$H", r)
}, d.minute = function(t) {
return this.$g(t, "$m", n)
}, d.second = function(t) {
return this.$g(t, "$s", e)
}, d.millisecond = function(e) {
return this.$g(e, "$ms", t)
}, d.unix = function() {
return Math.floor(this.valueOf() / 1e3)
}, d.valueOf = function() {
return this.$d.getTime()
}, d.startOf = function(t, o) {
var h = this,
f = !!D.u(o) || o,
c = D.p(t),
d = function(t, e) {
var n = D.w(h.$u ? Date.UTC(h.$y, e, t) : new Date(h.$y, e, t), h);
return f ? n : n.endOf(i)
},
$ = function(t, e) {
return D.w(h.toDate()[t].apply(h.toDate("s"), (f ? [0, 0, 0, 0] : [23, 59, 59, 999])
.slice(e)), h)
},
l = this.$W,
m = this.$M,
y = this.$D,
M = "set" + (this.$u ? "UTC" : "");
switch (c) {
case a:
return f ? d(1, 0) : d(31, 11);
case u:
return f ? d(1, m) : d(0, m + 1);
case s:
var g = this.$locale().weekStart || 0,
v = (l < g ? l + 7 : l) - g;
return d(f ? y - v : y + (6 - v), m);
case i:
case "date":
return $(M + "Hours", 0);
case r:
return $(M + "Minutes", 1);
case n:
return $(M + "Seconds", 2);
case e:
return $(M + "Milliseconds", 3);
default:
return this.clone()
}
}, d.endOf = function(t) {
return this.startOf(t, !1)
}, d.$set = function(s, o) {
var h, f = D.p(s),
c = "set" + (this.$u ? "UTC" : ""),
d = (h = {}, h[i] = c + "Date", h.date = c + "Date", h[u] = c + "Month", h[a] = c +
"FullYear", h[r] = c + "Hours", h[n] = c + "Minutes", h[e] = c + "Seconds", h[t] = c +
"Milliseconds", h)[f],
$ = f === i ? this.$D + (o - this.$W) : o;
if (f === u || f === a) {
var l = this.clone().set("date", 1);
l.$d[d]($), l.init(), this.$d = l.set("date", Math.min(this.$D, l.daysInMonth())).toDate()
} else d && this.$d[d]($);
return this.init(), this
}, d.set = function(t, e) {
return this.clone().$set(t, e)
}, d.get = function(t) {
return this[D.p(t)]()
}, d.add = function(t, o) {
var h, f = this;
t = Number(t);
var c = D.p(o),
d = function(e) {
var n = g(f);
return D.w(n.date(n.date() + Math.round(e * t)), f)
};
if (c === u) return this.set(u, this.$M + t);
if (c === a) return this.set(a, this.$y + t);
if (c === i) return d(1);
if (c === s) return d(7);
var $ = (h = {}, h[n] = 6e4, h[r] = 36e5, h[e] = 1e3, h)[c] || 1,
l = this.$d.getTime() + t * $;
return D.w(l, this)
}, d.subtract = function(t, e) {
return this.add(-1 * t, e)
}, d.format = function(t) {
var e = this;
if (!this.isValid()) return "Invalid Date";
var n = t || "YYYY-MM-DDTHH:mm:ssZ",
r = D.z(this),
i = this.$locale(),
s = this.$H,
u = this.$m,
o = this.$M,
a = i.weekdays,
h = i.months,
c = function(t, r, i, s) {
return t && (t[r] || t(e, n)) || i[r].substr(0, s)
},
d = function(t) {
return D.s(s % 12 || 12, t, "0")
},
$ = i.meridiem || function(t, e, n) {
var r = t < 12 ? "AM" : "PM";
return n ? r.toLowerCase() : r
},
l = {
YY: String(this.$y).slice(-2),
YYYY: this.$y,
M: o + 1,
MM: D.s(o + 1, 2, "0"),
MMM: c(i.monthsShort, o, h, 3),
MMMM: h[o] || h(this, n),
D: this.$D,
DD: D.s(this.$D, 2, "0"),
d: String(this.$W),
dd: c(i.weekdaysMin, this.$W, a, 2),
ddd: c(i.weekdaysShort, this.$W, a, 3),
dddd: a[this.$W],
H: String(s),
HH: D.s(s, 2, "0"),
h: d(1),
hh: d(2),
a: $(s, u, !0),
A: $(s, u, !1),
m: String(u),
mm: D.s(u, 2, "0"),
s: String(this.$s),
ss: D.s(this.$s, 2, "0"),
SSS: D.s(this.$ms, 3, "0"),
Z: r
};
return n.replace(f, function(t, e) {
return e || l[t] || r.replace(":", "")
})
}, d.utcOffset = function() {
return 15 * -Math.round(this.$d.getTimezoneOffset() / 15)
}, d.diff = function(t, h, f) {
var c, d = D.p(h),
$ = g(t),
l = 6e4 * ($.utcOffset() - this.utcOffset()),
m = this - $,
y = D.m(this, $);
return y = (c = {}, c[a] = y / 12, c[u] = y, c[o] = y / 3, c[s] = (m - l) / 6048e5, c[i] = (m -
l) / 864e5, c[r] = m / 36e5, c[n] = m / 6e4, c[e] = m / 1e3, c)[d] || m, f ? y : D.a(y)
}, d.daysInMonth = function() {
return this.endOf(u).$D
}, d.$locale = function() {
return m[this.$L]
}, d.locale = function(t, e) {
if (!t) return this.$L;
var n = this.clone(),
r = M(t, e, !0);
return r && (n.$L = r), n
}, d.clone = function() {
return D.w(this.$d, this)
}, d.toDate = function() {
return new Date(this.valueOf())
}, d.toJSON = function() {
return this.isValid() ? this.toISOString() : null
}, d.toISOString = function() {
return this.$d.toISOString()
}, d.toString = function() {
return this.$d.toUTCString()
}, c
}();
return g.prototype = v.prototype, g.extend = function(t, e) {
return t(e, v, g), g
}, g.locale = M, g.isDayjs = y, g.unix = function(t) {
return g(1e3 * t)
}, g.en = m[l], g.Ls = m, g
});

View File

@ -0,0 +1,107 @@
<template>
<view style="touch-action: none;">
<view class="home" style="position:fixed;" :style="{ top: top + 'px'}" id="right-nav" @touchmove.stop.prevent="setTouchMove">
<view class="homeCon bg-color-red" :class="homeActive === true ? 'on' : ''" v-if="homeActive">
<navigator hover-class='none' url='/pages/index/index' open-type='switchTab'
class='iconfont icon-shouye-xianxing' />
<navigator hover-class='none' url='/pages/order_addcart/order_addcart' open-type='switchTab'
class='iconfont icon-caigou-xianxing' />
<navigator hover-class='none' url='/pages/user/index' open-type='switchTab'
class='iconfont icon-yonghu1' />
</view>
<view @click="open" class="pictrueBox">
<view class="pictrue">
<image :src="homeActive === true ? '/static/images/close.gif' : '/static/images/open.gif'" class="image" />
</view>
</view>
</view>
</view>
</template>
<script>
import {
mapGetters
} from "vuex";
export default {
name: "Home",
props: {},
data: function() {
return {
top: "500"
};
},
computed: mapGetters(["homeActive"]),
methods: {
setTouchMove(e) {
if (e.touches[0].clientY < 545 && e.touches[0].clientY > 66) {
this.top = e.touches[0].clientY
}
},
open: function() {
this.homeActive ?
this.$store.commit("CLOSE_HOME") :
this.$store.commit("OPEN_HOME");
}
}
};
</script>
<style scoped>
.pictrueBox {
width: 130rpx;
height: 120rpx;
}
/*返回主页按钮*/
.home {
position: fixed;
color: white;
text-align: center;
z-index: 9999;
right: 15rpx;
display: flex;
}
.home .homeCon {
border-radius: 50rpx;
opacity: 0;
height: 0;
color: $theme-color;
width: 0;
}
.home .homeCon.on {
opacity: 1;
animation: bounceInRight 0.5s cubic-bezier(0.215, 0.610, 0.355, 1.000);
width: 300rpx;
height: 86rpx;
margin-bottom: 20rpx;
display: flex;
justify-content: center;
align-items: center;
background: #f44939 !important;
}
.home .homeCon .iconfont {
font-size: 48rpx;
color: #fff;
display: inline-block;
margin: 0 auto;
}
.home .pictrue {
width: 86rpx;
height: 86rpx;
border-radius: 50%;
margin: 0 auto;
}
.home .pictrue .image {
width: 100%;
height: 100%;
border-radius: 50%;
transform: rotate(90deg);
ms-transform: rotate(90deg);
moz-transform: rotate(90deg);
webkit-transform: rotate(90deg);
o-transform: rotate(90deg);
}
</style>

File diff suppressed because one or more lines are too long

20
sheep/api/member/level.js Normal file
View File

@ -0,0 +1,20 @@
import request from '@/sheep/request';
const getExper = {
// 获得会员等级列表
getLevelList: () => {
return request({
url: '/member/level/list',
method: 'GET',
});
},
// 获得会员经验记录分页
getExperienceRecordPage: () => {
return request({
url: '/member/experience-record/page',
method: 'GET',
});
},
};
export default getExper;

View File

@ -1,12 +1,26 @@
import request from '@/sheep/request';
const SpuApi = {
// 获得商品促销列表
getSpusales: (params) => {
return request({
url:'/product/spu/get-recommend-page',
method: 'GET',
params,
custom: {
showLoading: false,
showError: false,
},
});
},
// 获得商品 SPU 列表
getSpuListByIds: (ids) => {
return request({
url: '/product/spu/list-by-ids',
method: 'GET',
params: { ids },
params: {
ids
},
custom: {
showLoading: false,
showError: false,
@ -30,7 +44,38 @@ const SpuApi = {
return request({
url: '/product/spu/get-detail',
method: 'GET',
params: { id },
params: {
id
},
custom: {
showLoading: false,
showError: false,
},
});
},
//获取拼团列表接口
getSpulist: (id) => {
return request({
url: '/promotion/combination-activity/spuList',
method: 'GET',
params: {
count:3
},
custom: {
showLoading: false,
showError: false,
},
});
},
//获取秒杀列表接口
getSpuSeckilllist: (id) => {
return request({
url: '/promotion/seckill-activity/spuList',
method: 'GET',
params: {
count:3
},
custom: {
showLoading: false,
showError: false,

View File

@ -0,0 +1,30 @@
import request from '@/sheep/request';
const PointApi = {
// 获得积分商城活动分页
getPointActivityPage: (params) => {
return request({ url: 'promotion/point-activity/page', method: 'GET', params });
},
// 获得积分商城活动列表,基于活动编号数组
getPointActivityListByIds: (ids) => {
return request({
url: '/promotion/point-activity/list-by-ids',
method: 'GET',
params: {
ids,
},
});
},
// 获得积分商城活动明细
getPointActivity: (id) => {
return request({
url: 'promotion/point-activity/get-detail',
method: 'GET',
params: { id },
});
},
};
export default PointApi;

View File

@ -8,6 +8,14 @@ const DeliveryApi = {
method: 'get',
});
},
// 获得自提门店列表
getDeliveryPickUpStoreList: () => {
return request({
url: `/trade/delivery/pick-up-store/list`,
method: 'get',
});
},
};
export default DeliveryApi;

View File

@ -40,6 +40,8 @@
<s-groupon-block v-if="type === 'PromotionCombination'" :data="data" :styles="styles" />
<!-- 营销组件秒杀 -->
<s-seckill-block v-if="type === 'PromotionSeckill'" :data="data" :styles="styles" />
<!-- 营销组件积分商城 -->
<s-point-block v-if="type === 'PromotionPoint'" :data="data" :styles="styles" />
<!-- 营销组件小程序直播暂时没有这个功能 -->
<s-live-block v-if="type === 'MpLive'" :data="data" :styles="styles" />
<!-- 营销组件优惠券 -->
@ -66,6 +68,16 @@
<!-- 用户组件用户卡片 -->
<s-user-card v-if="type === 'UserCard'" />
<view v-if="type === 'UserOrder'" class="new-huiy"
@click="
sheep.$router.go('/pages/user/user_vip/index')
"
>
<view class="new-button">立即开通</view>
<img class="seckill1" mode="aspectFit"
src="https://zysc.fjptzykj.com:3000/shangcheng/64776e2edc3c2f15295e7c3976ba301e08f9170f99a2e845d8f33bd65179b177.png"
/>
</view>
<!-- 用户组件用户订单 -->
<s-order-card v-if="type === 'UserOrder'" :data="data" />
<!-- 用户组件用户资产 -->
@ -118,6 +130,35 @@
</script>
<style scoped lang="scss">
:deep(.uni-border-bottom){
height:0;
}
.new-huiy{
width:100%;
height:100px;
.new-button{
background:white;
padding:8px;
text-align:center;
position: absolute;
border-radius: 20px;
right: 29px;
top: 31px;
font-size:14px;
color: rgba(148, 109, 45, 1);
z-index: 33;
}
.seckill1{
position: absolute;
top: -71px;
z-index: 22;
/* left: 50%; */
/* transform: translateX(-50%); */
width: 94%;
}
}
.floxt {
width: 100%;
.addClass {

View File

@ -2,8 +2,9 @@
<template>
<scroll-view class="scroll-box" scroll-x scroll-anchoring>
<view class="coupon-box ss-flex">
<!-- couponList -->
<view
class="coupon-item"
class="coupon-item new-class"
:style="[couponBg, { marginLeft: `${data.space}px` }]"
v-for="(item, index) in couponList"
:key="index"
@ -116,16 +117,28 @@
}
await getCouponTemplateList();
}
//
// const getCouponTemplateList = async () => {
// const { data } = await CouponApi.getCouponTemplateListByIds(props.data.couponIds.join(','));
// couponList.value = data;
// };
//
const getCouponTemplateList = async () => {
const { data } = await CouponApi.getCouponTemplateListByIds(props.data.couponIds.join(','));
const { data } = await CouponApi.getCouponTemplateList();
couponList.value = data;
};
onMounted(() => {
getCouponTemplateList();
});
</script>
<style lang="scss" scoped>
.new-class{
margin: 0 10px !important;
margin-right: 2px !important;
}
.card-btn {
width: 140rpx;
height: 50rpx;
@ -145,8 +158,8 @@
}
}
.coupon-item {
&:nth-of-type(1) {
margin-left: 0 !important;
}
// &:nth-of-type(1) {
// margin-left: 0 !important;
// }
}
</style>

View File

@ -40,7 +40,7 @@
:class="isDisable ? 'disabled-color' : 'subtitle-color'"
v-if="data.validityType === 2"
>
有效期领取后 {{ data.fixedEndTerm }} 天内可用
有效期领取后{{ data.fixedStartTerm }}天开始至第{{ data.fixedEndTerm }}天内有效
</view>
<view class="sellby-text" :class="isDisable ? 'disabled-color' : 'subtitle-color'" v-else>
有效期: {{ sheep.$helper.timeFormat(data.validStartTime, 'yyyy-mm-dd') }}

View File

@ -0,0 +1,754 @@
<!-- 页面 -->
<template>
<view class="ss-goods-wrap">
<!-- xs卡片横向紧凑型一行放两个图片左内容右边 -->
<view
v-if="size === 'xs'"
class="xs-goods-card ss-flex ss-col-stretch"
:style="[elStyles]"
@tap="onClick"
>
<view v-if="tagStyle.show" class="tag-icon-box">
<image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image>
</view>
<image
class="xs-img-box"
:src="sheep.$url.cdn(data.image || data.picUrl)"
mode="aspectFit"
></image>
<view
v-if="goodsFields.title?.show || goodsFields.name?.show || goodsFields.price?.show"
class="xs-goods-content ss-flex-col ss-row-around"
>
<view
v-if="goodsFields.title?.show || goodsFields.name?.show"
class="xs-goods-title ss-line-1"
:style="[{ color: titleColor, width: titleWidth ? titleWidth + 'rpx' : '' }]"
>
{{ data.title || data.name }}
</view>
<view
v-if="goodsFields.price?.show"
class="xs-goods-price font-OPPOSANS"
:style="[{ color: goodsFields.price.color }]"
>
<text class="price-unit ss-font-24">{{ priceUnit }}</text>
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
</view>
</view>
</view>
<!-- sm卡片竖向紧凑一行放三个图上内容下 -->
<view v-if="size === 'sm'" class="sm-goods-card ss-flex-col" :style="[elStyles]" @tap="onClick">
<view v-if="tagStyle.show" class="tag-icon-box">
<image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image>
</view>
<image
class="sm-img-box"
:src="sheep.$url.cdn(data.image || data.picUrl)"
mode="aspectFill"
></image>
<view
v-if="goodsFields.title?.show || goodsFields.name?.show || goodsFields.price?.show"
class="sm-goods-content"
:style="[{ color: titleColor, width: titleWidth ? titleWidth + 'rpx' : '' }]"
>
<view
v-if="goodsFields.title?.show || goodsFields.name?.show"
class="sm-goods-title ss-line-1 ss-m-b-16"
>
{{ data.title || data.name }}
</view>
<view
v-if="goodsFields.price?.show"
class="sm-goods-price font-OPPOSANS"
:style="[{ color: goodsFields.price.color }]"
>
<text class="price-unit ss-font-24">{{ priceUnit }}</text>
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
</view>
</view>
</view>
<!-- md卡片竖向一行放两个图上内容下 -->
<view v-if="size === 'md'" class="md-goods-card ss-flex-col" :style="[elStyles]" @tap="onClick">
<view v-if="tagStyle.show" class="tag-icon-box">
<image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image>
</view>
<image
class="md-img-box"
:src="sheep.$url.cdn(data.image || data.picUrl)"
mode="widthFix"
></image>
<view
class="md-goods-content ss-flex-col ss-row-around ss-p-b-20 ss-p-t-20 ss-p-x-16"
:id="elId"
>
<view
v-if="goodsFields.title?.show || goodsFields.name?.show"
class="md-goods-title ss-line-1"
:style="[{ color: titleColor, width: titleWidth ? titleWidth + 'rpx' : '' }]"
>
{{ data.title || data.name }}
</view>
<view
v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show"
class="md-goods-subtitle ss-m-t-16 ss-line-1"
:style="[{ color: subTitleColor, background: subTitleBackground }]"
>
{{ data.subtitle || data.introduction }}
</view>
<slot name="activity">
<view v-if="data.promos?.length" class="tag-box ss-flex-wrap ss-flex ss-col-center">
<view
class="activity-tag ss-m-r-10 ss-m-t-16"
v-for="item in data.promos"
:key="item.id"
>
{{ item.title }}
</view>
</view>
</slot>
<view class="ss-flex ss-col-bottom">
<view
v-if="goodsFields.price?.show"
class="md-goods-price ss-m-t-16 font-OPPOSANS ss-m-r-10"
:style="[{ color: goodsFields.price.color }]"
>
<text class="price-unit ss-font-24">{{ priceUnit }}</text>
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
</view>
<view
v-if="
(goodsFields.original_price?.show || goodsFields.marketPrice?.show) &&
(data.original_price > 0 || data.marketPrice > 0)
"
class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex"
:style="[{ color: originPriceColor }]"
>
<text class="price-unit ss-font-20">{{ priceUnit }}</text>
<view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view>
</view>
</view>
<view class="ss-m-t-16 ss-flex ss-col-center ss-flex-wrap">
<view class="sales-text">{{ salesAndStock }}</view>
</view>
</view>
<slot name="cart">
<view class="cart-box ss-flex ss-col-center ss-row-center">
<image class="cart-icon" src="/static/img/shop/tabbar/category2.png" mode="" />
</view>
</slot>
</view>
<!-- lg卡片横向型一行放一个图片左内容右边 -->
<view
v-if="size === 'lg'"
class="lg-goods-card ss-flex ss-col-stretch"
:style="[elStyles]"
@tap="onClick"
>
<view v-if="tagStyle.show" class="tag-icon-box">
<image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image>
</view>
<view v-if="seckillTag" class="seckill-tag ss-flex ss-row-center"> 秒杀 </view>
<view v-if="grouponTag" class="groupon-tag ss-flex ss-row-center">
<view class="tag-icon">拼团</view>
</view>
<image
class="lg-img-box"
:src="sheep.$url.cdn(data.image || data.picUrl)"
mode="aspectFill"
></image>
<view class="lg-goods-content ss-flex-1 ss-flex-col ss-row-between ss-p-b-10 ss-p-t-20">
<view>
<view
v-if="goodsFields.title?.show || goodsFields.name?.show"
class="lg-goods-title ss-line-2"
:style="[{ color: titleColor }]"
>
{{ data.title || data.name }}
</view>
<view
v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show"
class="lg-goods-subtitle ss-m-t-10 ss-line-1"
:style="[{ color: subTitleColor, background: subTitleBackground }]"
>
{{ data.subtitle || data.introduction }}
</view>
</view>
<view>
<slot name="activity">
<view v-if="data.promos?.length" class="tag-box ss-flex ss-col-center">
<view class="activity-tag ss-m-r-10" v-for="item in data.promos" :key="item.id">
{{ item.title }}
</view>
</view>
</slot>
<view class="ss-flex ss-col-bottom ss-m-t-10">
<view
v-if="goodsFields.price?.show"
class="lg-goods-price ss-m-r-12 ss-flex ss-col-bottom font-OPPOSANS"
:style="[{ color: goodsFields.price.color }]"
>
<text class="ss-font-24">{{ priceUnit }}</text>
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
</view>
<view
v-if="
(goodsFields.original_price?.show || goodsFields.marketPrice?.show) &&
(data.original_price > 0 || data.marketPrice > 0)
"
class="goods-origin-price ss-flex ss-col-bottom font-OPPOSANS"
:style="[{ color: originPriceColor }]"
>
<text class="price-unit ss-font-20">{{ priceUnit }}</text>
<view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view>
</view>
</view>
<view class="ss-m-t-8 ss-flex ss-col-center ss-flex-wrap">
<view class="sales-text">{{ salesAndStock }}</view>
</view>
</view>
</view>
<slot name="cart">
<view class="buy-box ss-flex ss-col-center ss-row-center" v-if="buttonShow"> 立即兑换 </view>
</slot>
</view>
<!-- sl卡片竖向型一行放一个图片上内容下边 -->
<view v-if="size === 'sl'" class="sl-goods-card ss-flex-col" :style="[elStyles]" @tap="onClick">
<view v-if="tagStyle.show" class="tag-icon-box">
<image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image>
</view>
<image
class="sl-img-box"
:src="sheep.$url.cdn(data.image || data.picUrl)"
mode="aspectFill"
></image>
<view class="sl-goods-content">
<view>
<view
v-if="goodsFields.title?.show || goodsFields.name?.show"
class="sl-goods-title ss-line-1"
:style="[{ color: titleColor }]"
>
{{ data.title || data.name }}
</view>
<view
v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show"
class="sl-goods-subtitle ss-m-t-16"
:style="[{ color: subTitleColor, background: subTitleBackground }]"
>
{{ data.subtitle || data.introduction }}
</view>
</view>
<view>
<slot name="activity">
<view v-if="data.promos?.length" class="tag-box ss-flex ss-col-center ss-flex-wrap">
<view
class="activity-tag ss-m-r-10 ss-m-t-16"
v-for="item in data.promos"
:key="item.id"
>
{{ item.title }}
</view>
</view>
</slot>
<view v-if="goodsFields.price?.show" class="ss-flex ss-col-bottom font-OPPOSANS">
<view class="sl-goods-price ss-m-r-12" :style="[{ color: goodsFields.price.color }]">
<text class="price-unit ss-font-24">{{ priceUnit }}</text>
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
</view>
<view
v-if="
(goodsFields.original_price?.show || goodsFields.marketPrice?.show) &&
(data.original_price > 0 || data.marketPrice > 0)
"
class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex"
:style="[{ color: originPriceColor }]"
>
<text class="price-unit ss-font-20">{{ priceUnit }}</text>
<view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view>
</view>
</view>
<view class="ss-m-t-16 ss-flex ss-flex-wrap">
<view class="sales-text">{{ salesAndStock }}</view>
</view>
</view>
</view>
<slot name="cart"
><view class="buy-box ss-flex ss-col-center ss-row-center">立即兑换</view></slot
>
</view>
</view>
</template>
<script setup>
/**
* 商品卡片
*
* @property {Array} size = [xs | sm | md | lg | sl ] - 列表数据
* @property {String} tag - md及以上才有
* @property {String} img - 图片
* @property {String} background - 背景色
* @property {String} topRadius - 上圆角
* @property {String} bottomRadius - 下圆角
* @property {String} title - 标题
* @property {String} titleColor - 标题颜色
* @property {Number} titleWidth = 0 - 标题宽度默认0单位rpx
* @property {String} subTitle - 副标题
* @property {String} subTitleColor - 副标题颜色
* @property {String} subTitleBackground - 副标题背景
* @property {String | Number} price - 价格
* @property {String} priceColor - 价格颜色
* @property {String | Number} originPrice - 原价/划线价
* @property {String} originPriceColor - 原价颜色
* @property {String | Number} sales - 销售数量
* @property {String} salesColor - 销售数量颜色
*
* @slots activity - 活动插槽
* @slots cart - 购物车插槽默认包含文字背景色文字颜色 || 图片 || 行为
*
* @event {Function()} click - 点击卡片
*
*/
import { computed, reactive, getCurrentInstance, onMounted, nextTick } from 'vue';
import sheep from '@/sheep';
import { fen2yuan, formatSales } from '@/sheep/hooks/useGoods';
import { formatStock } from '@/sheep/hooks/useGoods';
import goodsCollectVue from '@/pages/user/goods-collect.vue';
import { isArray } from 'lodash';
//
const state = reactive({});
//
const props = defineProps({
goodsFields: {
type: [Array, Object],
default() {
return {
//
price: { show: true },
//
stock: { show: true },
//
name: { show: true },
//
introduction: { show: true },
//
marketPrice: { show: true },
//
salesCount: { show: true },
};
},
},
tagStyle: {
type: Object,
default: {},
},
data: {
type: Object,
default: {},
},
size: {
type: String,
default: 'sl',
},
background: {
type: String,
default: '',
},
topRadius: {
type: Number,
default: 0,
},
bottomRadius: {
type: Number,
default: 0,
},
titleWidth: {
type: Number,
default: 0,
},
titleColor: {
type: String,
default: '#333',
},
priceColor: {
type: String,
default: '',
},
originPriceColor: {
type: String,
default: '#C4C4C4',
},
priceUnit: {
type: String,
default: '¥',
},
subTitleColor: {
type: String,
default: '#999999',
},
subTitleBackground: {
type: String,
default: '',
},
buttonShow: {
type: Boolean,
default: true,
},
seckillTag: {
type: Boolean,
default: false,
},
grouponTag: {
type: Boolean,
default: false,
},
});
//
const elStyles = computed(() => {
return {
background: props.background,
'border-top-left-radius': props.topRadius + 'px',
'border-top-right-radius': props.topRadius + 'px',
'border-bottom-left-radius': props.bottomRadius + 'px',
'border-bottom-right-radius': props.bottomRadius + 'px',
};
});
//
const salesAndStock = computed(() => {
let text = [];
if (props.goodsFields.salesCount?.show) {
text.push(formatSales(props.data.sales_show_type, props.data.salesCount));
}
if (props.goodsFields.stock?.show) {
text.push(formatStock(props.data.stock_show_type, props.data.stock));
}
return text.join(' | ');
});
//
const emits = defineEmits(['click', 'getHeight']);
const onClick = () => {
emits('click');
};
//
const { proxy } = getCurrentInstance();
const elId = `sheep_${Math.ceil(Math.random() * 10e5).toString(36)}`;
function getGoodsPriceCardWH() {
if (props.size === 'md') {
const view = uni.createSelectorQuery().in(proxy);
view.select(`#${elId}`).fields({ size: true, scrollOffset: true });
view.exec((data) => {
let totalHeight = 0;
const goodsPriceCard = data[0];
if (props.data.image_wh) {
totalHeight =
(goodsPriceCard.width / props.data.image_wh.w) * props.data.image_wh.h +
goodsPriceCard.height;
} else {
totalHeight = goodsPriceCard.width;
}
emits('getHeight', totalHeight);
});
}
}
onMounted(() => {
nextTick(() => {
getGoodsPriceCardWH();
});
});
</script>
<style lang="scss" scoped>
.tag-icon-box {
position: absolute;
left: 0;
top: 0;
z-index: 2;
.tag-icon {
width: 72rpx;
height: 44rpx;
}
}
.seckill-tag {
position: absolute;
left: 0;
top: 0;
z-index: 2;
width: 68rpx;
height: 38rpx;
background: linear-gradient(90deg, #ff5854 0%, #ff2621 100%);
border-radius: 10rpx 0px 10rpx 0px;
font-size: 24rpx;
font-weight: 500;
color: #ffffff;
line-height: 32rpx;
}
.groupon-tag {
position: absolute;
left: 0;
top: 0;
z-index: 2;
width: 68rpx;
height: 38rpx;
background: linear-gradient(90deg, #fe832a 0%, #ff6600 100%);
border-radius: 10rpx 0px 10rpx 0px;
font-size: 24rpx;
font-weight: 500;
color: #ffffff;
line-height: 32rpx;
}
.goods-img {
width: 100%;
height: 100%;
background-color: #f5f5f5;
}
.price-unit {
margin-right: -4px;
}
.sales-text {
display: table;
font-size: 24rpx;
transform: scale(0.8);
margin-left: 0rpx;
color: #c4c4c4;
}
.activity-tag {
font-size: 20rpx;
color: #ff0000;
line-height: 30rpx;
padding: 0 10rpx;
border: 1px solid rgba(#ff0000, 0.25);
border-radius: 4px;
flex-shrink: 0;
}
.goods-origin-price {
font-size: 20rpx;
color: #c4c4c4;
line-height: 36rpx;
text-decoration: line-through;
}
// xs
.xs-goods-card {
overflow: hidden;
// max-width: 375rpx;
background-color: $white;
position: relative;
.xs-img-box {
width: 128rpx;
height: 128rpx;
margin-right: 20rpx;
}
.xs-goods-title {
font-size: 26rpx;
color: #333;
font-weight: 500;
}
.xs-goods-price {
font-size: 30rpx;
color: $red;
}
}
// sm
.sm-goods-card {
overflow: hidden;
// width: 223rpx;
// width: 100%;
background-color: $white;
position: relative;
padding: 0 10px;
padding-top: 10px;
.sm-img-box {
// width: 228rpx;
width: 100%;
height: 208rpx;
}
.sm-goods-content {
padding: 20rpx 16rpx;
box-sizing: border-box;
}
.sm-goods-title {
font-size: 26rpx;
color: #333;
}
.sm-goods-price {
font-size: 30rpx;
color: $red;
}
}
// md
.md-goods-card {
overflow: hidden;
width: auto;
padding: 10px 10px;
position: relative;
z-index: 1;
background-color: $white;
position: relative;
.md-img-box {
width: 100%;
}
.md-goods-title {
font-size: 26rpx;
color: #333;
width: 100%;
}
.md-goods-subtitle {
font-size: 24rpx;
font-weight: 400;
color: #999999;
}
.md-goods-price {
font-size: 30rpx;
color: $red;
line-height: 36rpx;
}
.cart-box {
width: 54rpx;
height: 54rpx;
background: linear-gradient(90deg, #fe8900, #ff5e00);
border-radius: 50%;
position: absolute;
bottom: 50rpx;
right: 20rpx;
z-index: 2;
.cart-icon {
width: 30rpx;
height: 30rpx;
}
}
}
// lg
.lg-goods-card {
overflow: hidden;
position: relative;
z-index: 1;
background-color: $white;
height: 280rpx;
.lg-img-box {
width: 280rpx;
height: 280rpx;
margin-right: 20rpx;
}
.lg-goods-title {
font-size: 28rpx;
font-weight: 500;
color: #333333;
// line-height: 36rpx;
// width: 410rpx;
}
.lg-goods-subtitle {
font-size: 24rpx;
font-weight: 400;
color: #999999;
// line-height: 30rpx;
// width: 410rpx;
}
.lg-goods-price {
font-size: 30rpx;
color: $red;
line-height: 36rpx;
}
.buy-box {
position: absolute;
bottom: 20rpx;
right: 20rpx;
z-index: 2;
width: 120rpx;
height: 50rpx;
background: linear-gradient(90deg, #fe8900, #ff5e00);
border-radius: 25rpx;
font-size: 24rpx;
color: #ffffff;
}
.tag-box {
width: 100%;
}
}
// sl
.sl-goods-card {
overflow: hidden;
position: relative;
z-index: 1;
width: 100%;
background-color: $white;
.sl-goods-content {
padding: 20rpx 20rpx;
box-sizing: border-box;
}
.sl-img-box {
width: 100%;
height: 360rpx;
}
.sl-goods-title {
font-size: 26rpx;
color: #333;
font-weight: 500;
}
.sl-goods-subtitle {
font-size: 24rpx;
font-weight: 400;
color: #999999;
line-height: 30rpx;
}
.sl-goods-price {
font-size: 30rpx;
color: $red;
line-height: 36rpx;
}
.buy-box {
position: absolute;
bottom: 20rpx;
right: 20rpx;
z-index: 2;
width: 148rpx;
height: 50rpx;
background: linear-gradient(90deg, #fe8900, #ff5e00);
border-radius: 25rpx;
font-size: 24rpx;
color: #ffffff;
}
}
</style>

View File

@ -485,6 +485,7 @@
.tag-icon {
width: 72rpx;
height: 44rpx;
border-radius:8px;
}
}
.seckill-tag {
@ -580,11 +581,14 @@
// width: 100%;
background-color: $white;
position: relative;
padding: 0 10px;
padding-top: 10px;
.sm-img-box {
// width: 228rpx;
width: 100%;
height: 208rpx;
border-radius:8px;
}
.sm-goods-content {
padding: 20rpx 16rpx;
@ -604,7 +608,8 @@
// md
.md-goods-card {
overflow: hidden;
width: 100%;
width: auto;
padding: 10px 10px;
position: relative;
z-index: 1;
background-color: $white;

View File

@ -1,62 +1,60 @@
<!-- 装修组件 - 拼团 -->
<template>
<view class="new-class">
<!-- 标题栏 -->
<view class="menu-list-wrap">
<uni-list :border="true">
<uni-list-item showArrow clickable
@tap="sheep.$router.go('/pages/activity/groupon/list')">
<template v-slot:header>
<view>
<view
v-if="layoutType === 'threeCol'"
class="goods-sm-box ss-flex ss-flex-wrap"
:style="[{ margin: '-' + data.space + 'rpx' }]"
>
<view
v-for="product in productList"
:key="product.id"
class="goods-card-box"
:style="[
<view class="wh">
<img class="new-text1"
src="https://zysc.fjptzykj.com:3000/shangcheng/2f2be070c60ceb9466af937ff9dd8917ad2ee02f774dbac48fbb9e73bfc688d0.png" />
<span class="new-text">拼团活动</span>
<view style="color: rgb(187, 187, 187);font-size:15px;" class="title-text ss-flex ss-row-center ss-col-center ss-m-l-20">
92人拼团成功
</view>
</view>
</view>
</template>
<template v-slot:footer>
<view style="color: rgb(187, 187, 187);font-size:15px;" class="notice-text ss-flex ss-row-center ss-col-center">
查看更多
</view>
</template>
</uni-list-item>
</uni-list>
</view>
<!-- <view v-if="layoutType === 'threeCol'" class="goods-sm-box ss-flex ss-flex-wrap"
:style="[{ margin: '-' + data.space + 'rpx' }]">
<view v-for="product in productList" :key="product.id" class="goods-card-box" :style="[
{
padding: data.space + 'rpx',
},
]"
>
<s-goods-column
class="goods-card"
size="sm"
:goodsFields="data.fields"
:tagStyle="tagStyle"
:data="product"
:titleColor="data.fields.name?.color"
:topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom"
@click="
]">
<s-goods-column class="goods-card" size="sm" :goodsFields="data.fields" :tagStyle="tagStyle"
:data="product" :titleColor="data.fields.name?.color" :topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom" @click="
sheep.$router.go('/pages/goods/groupon', {
id: props.data.activityId,
})
"
></s-goods-column>
</view>
"></s-goods-column>
</view>
</view> -->
<!-- 样式2 一行一个 图片左 文案右 -->
<view class="goods-box" v-if="layoutType === 'oneCol'">
<view
class="goods-list"
v-for="(product, index) in productList"
:key="index"
:style="[{ marginBottom: space + 'px' }]"
>
<s-goods-column
class="goods-card"
size="lg"
:goodsFields="data.fields"
:tagStyle="tagStyle"
:data="product"
:titleColor="data.fields.name?.color"
:subTitleColor="data.fields.introduction?.color"
:topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom"
@click="
<!-- <view class="goods-box" v-if="layoutType === 'oneCol'">
<view class="goods-list" v-for="(product, index) in productList" :key="index"
:style="[{ marginBottom: space + 'px' }]">
<s-goods-column class="goods-card" size="lg" :goodsFields="data.fields" :tagStyle="tagStyle"
:data="product" :titleColor="data.fields.name?.color"
:subTitleColor="data.fields.introduction?.color" :topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom" @click="
sheep.$router.go('/pages/goods/groupon', {
id: props.data.activityId,
})
"
>
">
<template v-slot:cart>
<button class="ss-reset-button cart-btn" :style="[buyStyle]">
{{ btnBuy?.type === 'text' ? btnBuy.text : '' }}
@ -64,15 +62,38 @@
</template>
</s-goods-column>
</view>
</view> -->
<view v-if="'threeCol' === 'threeCol'" class="goods-sm-box ss-flex ss-flex-wrap"
:style="[{ margin: '-' + data.space + 'rpx' }]">
<!-- productList -->
<view v-for="product in productList" :key="product.id" class="goods-card-box" :style="[
{
padding: data.space + 'rpx',
},
]">
<s-goods-column class="goods-card" size="sm" :goodsFields="data.fields" :tagStyle="tagStyle"
:data="product" :titleColor="data.fields.name?.color" :topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom" @click="
sheep.$router.go('/pages/goods/groupon', {
id: product.activityId,
})
"></s-goods-column>
</view>
</view>
</view>
</template>
<script setup>
/**
* 拼团
*/
import { computed, onMounted, ref } from 'vue';
import {
computed,
onMounted,
ref
} from 'vue';
import sheep from '@/sheep';
import SpuApi from '@/sheep/api/product/spu';
import CombinationApi from '@/sheep/api/promotion/combination';
@ -89,8 +110,16 @@
},
});
let { layoutType, tagStyle, btnBuy, space } = props.data;
let { marginLeft, marginRight } = props.styles;
let {
layoutType,
tagStyle,
btnBuy,
space
} = props.data;
let {
marginLeft,
marginRight
} = props.styles;
//
const buyStyle = computed(() => {
@ -114,15 +143,53 @@
const productList = ref([]);
onMounted(async () => {
// todo@owen Yudao
const { data: activity } = await CombinationApi.getCombinationActivity(props.data.activityId);
const { data: spu } = await SpuApi.getSpuDetail(activity.spuId);
productList.value = [spu];
const {
data: activity
} = await CombinationApi.getCombinationActivity(props.data.activityId);
const ss = await SpuApi.getSpulist();
console.log(ss, "getSpuListByIds")
productList.value = ss.data;
});
</script>
<style lang="scss">
:deep(.uni-list--border-bottom){
height:0 !important;
}
:deep(.container--right){
padding-left: 5px !important;
}
.ss-col-center{
.list-icon {
position: relative;
width: 93px;
height: 40px;
padding-right: 10px;
&::after{
position:absolute;
content:'';
top:50%;
right:0;
width:1px;
height:57%;
border-right:1px solid #ababab;
transform: translateY(-50%);
}
}
}
.notice-text {}
.menu-list-wrap {
::v-deep .uni-list {
background-color: transparent;
}
}
</style>
<style lang="scss" scoped>
.goods-list {
position: relative;
.cart-btn {
position: absolute;
bottom: 10rpx;
@ -136,14 +203,17 @@
color: #fff;
}
}
.goods-list {
&:nth-last-of-type(1) {
margin-bottom: 0 !important;
}
}
.goods-sm-box {
margin: 0 auto;
box-sizing: border-box;
.goods-card-box {
flex-shrink: 0;
overflow: hidden;
@ -151,4 +221,40 @@
box-sizing: border-box;
}
}
.new-class {
background: white;
border-radius: 8px;
}
:deep(.sm-goods-card) {
background: transparent;
}
.wh {
display: flex;
align-items: center;
.new-text1{
width:30px;
height:30px;
}
.new-text{
position: relative;
font-weight: 700;
padding-right: 10px;
&::after {
position: absolute;
content: "";
top: 50%;
right: 0;
width: 1px;
height: 57%;
border-right: 1px solid #ababab;
transform: translateY(-50%);
}
}
}
</style>

View File

@ -1,19 +1,19 @@
<!-- 装修基础组件菜单导航金刚区 -->
<template>
<view>
<view class="title">
<!-- <view class="title">
我的服务
</view>
</view> -->
<!-- 包裹层 -->
<view class="ui-swiper" :class="[props.mode, props.bg, props.ui]"
:style="[{ height: swiperHeight + (menuList.length > 1 ? 50 : 0) + 'rpx' }]">
<!-- <view class="ui-swiper" :class="[props.mode, props.bg, props.ui]"
:style="[{ height: swiperHeight + (menuList.length > 1 ? 50 : 0) + 'rpx' }]"> -->
<!-- 轮播 -->
<swiper :circular="props.circular" :current="state.cur" :autoplay="props.autoplay"
<!-- <swiper :circular="props.circular" :current="state.cur" :autoplay="props.autoplay"
:interval="props.interval" :duration="props.duration" :style="[{ height: swiperHeight + 'rpx' }]"
@change="swiperChange">
<swiper-item v-for="(arr, index) in menuList" :key="index" :class="{ cur: state.cur == index }">
@change="swiperChange"> -->
<!-- <swiper-item v-for="(arr, index) in menuList" :key="index" :class="{ cur: state.cur == index }"> -->
<!-- 宫格 -->
<view class="grid-wrap">
<!-- <view class="grid-wrap">
<view v-for="(item, index) in arr" :key="index"
class="grid-item ss-flex ss-flex-col ss-col-center ss-row-center"
:style="[{ width: `${100 * (1 / data.column)}%`, height: '200rpx' }]"
@ -35,11 +35,11 @@
</view>
</view>
</view>
</view>
</swiper-item>
</swiper>
</view> -->
<!-- </swiper-item>
</swiper> -->
<!-- 指示点 -->
<template v-if="menuList.length > 1">
<!-- <template v-if="menuList.length > 1">
<view class="ui-swiper-dot" :class="props.dotStyle" v-if="props.dotStyle != 'tag'">
<view class="line-box" v-for="(item, index) in menuList.length" :key="index"
:class="[state.cur == index ? 'cur' : '', props.dotCur]"></view>
@ -50,7 +50,30 @@
</view>
</view>
</template>
</view> -->
<view class="newList">
<view class="new_menu" v-for="(arr, index) in menuList" :key="index">
<view v-for="(item, index) in arr" :key="index"
class="new_items"
:style="[{ width: `${100 * (1 / data.column)}%`}]"
@tap="sheep.$router.go(item.url)">
<view class="menu-box ss-flex ss-flex-col ss-col-center ss-row-center">
<view v-if="item.badge.show" class="tag-box">
{{ item.badge.text }}
</view>
<image v-if="item.iconUrl" class="menu-icon" :src="sheep.$url.cdn(item.iconUrl)"
mode="aspectFill"></image>
<view v-if="data.layout === 'iconText'" class="menu-title"
:style="[{ color: item.titleColor }]">
{{ item.title }}
</view>
</view>
</view>
</view>
</view>
</view>
</template>
@ -212,13 +235,22 @@
</script>
<style lang="scss" scoped>
.new_menu{
display:flex;
flex-wrap:wrap;
.new_items{
width:25%;
margin-bottom:20px;
}
}
.title {
padding: 10px 20px;
height: 20px;
padding: 10px 10px;
height: 0px;
line-height: 20px;
font-size: 16px;
font-weight: 600;
border-bottom: 1px solid #dcdcdc;
// border-bottom: 1px solid #dcdcdc;
}
.grid-wrap {
@ -252,8 +284,8 @@
.menu-icon {
transform: translate(0, 0);
width: 80rpx;
height: 80rpx;
width: 25px;
height: 28px;
padding-bottom: 10rpx;
}

View File

@ -44,8 +44,8 @@
<style lang="scss" scoped>
.menu-image {
width: 24px;
height: 24px;
width: 45px;
height: 45px;
}
.grid-item-box {
flex: 1;

View File

@ -2,34 +2,21 @@
<template>
<view class="menu-list-wrap">
<uni-list :border="true">
<uni-list-item
v-for="(item, index) in data.list"
:key="index"
showArrow
clickable
@tap="sheep.$router.go(item.url)"
>
<uni-list-item v-for="(item, index) in data.list" :key="index" showArrow clickable
@tap="sheep.$router.go(item.url)">
<template v-slot:header>
<view class="ss-flex ss-col-center">
<image
v-if="item.iconUrl"
class="list-icon"
:src="sheep.$url.cdn(item.iconUrl)"
mode="aspectFit"
></image>
<view
class="title-text ss-flex ss-row-center ss-col-center ss-m-l-20"
:style="[{ color: item.titleColor }]"
>
<image v-if="item.iconUrl" class="list-icon" :src="sheep.$url.cdn(item.iconUrl)"
mode="aspectFit"></image>
<view class="title-text ss-flex ss-row-center ss-col-center ss-m-l-20"
:style="[{ color: item.titleColor }]">
{{ item.title }}
</view>
</view>
</template>
<template v-slot:footer>
<view
class="notice-text ss-flex ss-row-center ss-col-center"
:style="[{ color: item.subtitleColor }]"
>
<view class="notice-text ss-flex ss-row-center ss-col-center"
:style="[{ color: item.subtitleColor }]">
{{ item.subtitle }}
</view>
</template>
@ -52,12 +39,31 @@
</script>
<style lang="scss">
:deep(.container--right){
padding-left: 5px !important;
}
.ss-col-center{
.list-icon {
width: 20px;
height: 20px;
position: relative;
width: 100px;
height: 40px;
padding-right: 10px;
&::after{
position:absolute;
content:'';
top:50%;
right:0;
width:1px;
height:57%;
border-right:1px solid #ababab;
transform: translateY(-50%);
}
.notice-text {
}
}
.notice-text {}
.menu-list-wrap {
::v-deep .uni-list {
background-color: transparent;

View File

@ -36,37 +36,37 @@
const list = [
{
url: '/pages/index/index',
icon: '/static/img/shop/tools/home.png',
icon: 'https://zysc.fjptzykj.com:3000/shangcheng/f4e03230b5cb9b2bf789b67df43125af1b3cef9c2abf4d8bca8f6fa5ded16a20.png',
title: '首页',
},
{
url: '/pages/index/search',
icon: '/static/img/shop/tools/search.png',
icon: 'https://zysc.fjptzykj.com:3000/shangcheng/96a288f2a0043c8defaa37e922828b3092ba785e1c191bf18f20dbd462261f7a.png',
title: '搜索',
},
{
url: '/pages/index/user',
icon: '/static/img/shop/tools/user.png',
icon: 'https://zysc.fjptzykj.com:3000/shangcheng/227699332b8ae736e220852e60215072eb2805478dab4909e085f89aeb3604cf.png',
title: '个人中心',
},
{
url: '/pages/index/cart',
icon: '/static/img/shop/tools/cart.png',
icon: 'https://zysc.fjptzykj.com:3000/shangcheng/a45981116198a65db5f28ffd070f0078cfa66ac932a0136bf45ba7e8f401a1d0.png',
title: '购物车',
},
{
url: '/pages/user/goods-log',
icon: '/static/img/shop/tools/browse.png',
icon: 'https://zysc.fjptzykj.com:3000/shangcheng/7e5ecfb841f2d89b778e1070ef867c17ccda48a5fea14a149f8eb1ce6aa26a87.png',
title: '浏览记录',
},
{
url: '/pages/user/goods-collect',
icon: '/static/img/shop/tools/collect.png',
icon: 'https://zysc.fjptzykj.com:3000/shangcheng/9f83f4dc3cbf8b1e8e747f8dd79a260feaf65fa9ef3f2e2224015779f85119a1.png',
title: '我的收藏',
},
{
url: '/pages/chat/index',
icon: '/static/img/shop/tools/service.png',
icon: 'https://zysc.fjptzykj.com:3000/shangcheng/739f3165045b1552b71176297dab45eda2e192b976e25b1a458a8781a61b7557.png',
title: '客服',
},
];

View File

@ -1,8 +1,14 @@
<!-- 装修用户组件用户订单 -->
<template>
<view>
<view style="background:white;">
<view class="title">
订单中心
<span>订单中心</span>
<view class="ff">
<span class="ckgd" @click="sheep.$router.go('/pages/order/list');">查看全部</span>
<span class="ckgd" @click="sheep.$router.go('/pages/order/list');">
<image class="img" src="@/static/images/dayu.png"></image>
</span>
</view>
</view>
<view class="ss-order-menu-wrap ss-flex ss-col-center">
@ -16,7 +22,7 @@
<image v-if="index == 3" class="item-icon" :src="imag3" mode="aspectFit" />
<image v-if="index == 4" class="item-icon" :src="imag4" mode="aspectFit" />
</uni-badge>
<view class="menu-title ss-m-t-28">{{ item.title }}</view>
<view class="menu-title">{{ item.title }}</view>
</view>
</view>
</view>
@ -27,7 +33,7 @@
import imag1 from '@/static/images/no_take.png'
import imag2 from '@/static/images/no_comment.png'
import imag3 from '@/static/images/order.png'
import imag4 from '@/static/images/order.png'
import imag4 from '@/static/images/order2.png'
/**
* 装修组件 - 订单菜单组
*/
@ -44,6 +50,14 @@
type: 'unpaid',
count: 'unpaidCount',
},
{
title: '待发货',
value: '2',
icon: '/static/img/shop/order/no_take.png',
path: '/pages/order/list',
type: 'take',
count: 'undeliveredCount',
},
{
title: '待收货',
value: '3',
@ -61,32 +75,51 @@
count: 'uncommentedCount',
},
{
title: '售后',
title: '退款/售后',
value: '0',
icon: '/static/img/shop/order/change_order.png',
path: '/pages/order/aftersale/list',
type: 'aftersale',
count: 'afterSaleCount',
},
{
title: '全部订单',
value: '0',
icon: '/static/img/shop/order/all_order.png',
path: '/pages/order/list',
},
}
// ,
// {
// title: '',
// value: '0',
// icon: '/static/img/shop/order/all_order.png',
// path: '/pages/order/list',
// }
];
const numData = computed(() => sheep.$store('user').numData);
console.log(numData,'numData')
</script>
<style lang="scss" scoped>
.title {
padding: 10px 20px;
padding: 10px 10px;
height: 20px;
line-height: 20px;
font-size: 16px;
font-weight: 600;
border-bottom: 1px solid #dcdcdc;
// border-bottom: 1px solid #dcdcdc;
display:flex;
justify-content: space-between;
.ff{
display: flex;
align-items: center;
.ckgd{
color: #8a8787;
font-size: 15px;
.img{
width:20px;
height:20px;
margin-top: 3px;
}
}
}
}
.ss-order-menu-wrap {
@ -99,6 +132,7 @@
font-size: 24rpx;
line-height: 24rpx;
color: #333333;
margin-top:14rpx;
}
.item-icon {

View File

@ -0,0 +1,328 @@
<!-- 装修商品组件积分商城商品卡片 -->
<template>
<!-- 商品卡片 -->
<view>
<!-- 布局1. 单列大图上图下内容-->
<view
v-if="layoutType === LayoutTypeEnum.ONE_COL_BIG_IMG && state.spuList.length"
class="goods-sl-box"
>
<view
class="goods-box"
v-for="item in state.spuList"
:key="item.id"
:style="[{ marginBottom: data.space * 2 + 'rpx' }]"
>
<s-goods-column
class=""
size="sl"
:goodsFields="data.fields"
:tagStyle="data.badge"
:data="item"
:titleColor="data.fields.name?.color"
:subTitleColor="data.fields.introduction.color"
:topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom"
@click="sheep.$router.go('/pages/goods/point', { id: item.activityId })"
>
<!-- 购买按钮 -->
<template v-slot:cart>
<button class="ss-reset-button cart-btn" :style="[buyStyle]">
{{ btnBuy.type === 'text' ? btnBuy.text : '' }}
</button>
</template>
</s-goods-column>
</view>
</view>
<!-- 布局2. 单列小图左图右内容 -->
<view
v-if="layoutType === LayoutTypeEnum.ONE_COL_SMALL_IMG && state.spuList.length"
class="goods-lg-box"
>
<view
class="goods-box"
:style="[{ marginBottom: data.space + 'px' }]"
v-for="item in state.spuList"
:key="item.id"
>
<s-goods-column
class="goods-card"
size="lg"
:goodsFields="data.fields"
:data="item"
:tagStyle="data.badge"
:titleColor="data.fields.name?.color"
:subTitleColor="data.fields.introduction.color"
:topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom"
@tap="sheep.$router.go('/pages/goods/point', { id: item.activityId })"
>
<!-- 购买按钮 -->
<template v-slot:cart>
<button class="ss-reset-button cart-btn" :style="[buyStyle]">
{{ btnBuy.type === 'text' ? btnBuy.text : '' }}
</button>
</template>
</s-goods-column>
</view>
</view>
<!-- 布局3. 双列每一列上图下内容-->
<view
v-if="layoutType === LayoutTypeEnum.TWO_COL && state.spuList.length"
class="goods-md-wrap ss-flex ss-flex-wrap ss-col-top"
>
<view class="goods-list-box">
<view
class="left-list"
:style="[{ paddingRight: data.space + 'rpx', marginBottom: data.space + 'px' }]"
v-for="item in state.leftSpuList"
:key="item.id"
>
<s-goods-column
class="goods-md-box"
size="md"
:goodsFields="data.fields"
:tagStyle="data.badge"
:data="item"
:titleColor="data.fields.name?.color"
:subTitleColor="data.fields.introduction.color"
:topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom"
:titleWidth="330 - marginLeft - marginRight"
@click="sheep.$router.go('/pages/goods/point', { id: item.activityId })"
@getHeight="calculateGoodsColumn($event, 'left')"
>
<!-- 购买按钮 -->
<template v-slot:cart>
<button class="ss-reset-button cart-btn" :style="[buyStyle]">
{{ btnBuy.type === 'text' ? btnBuy.text : '' }}
</button>
</template>
</s-goods-column>
</view>
</view>
<view class="goods-list-box">
<view
class="right-list"
:style="[{ paddingLeft: data.space + 'rpx', marginBottom: data.space + 'px' }]"
v-for="item in state.rightSpuList"
:key="item.id"
>
<s-goods-column
class="goods-md-box"
size="md"
:goodsFields="data.fields"
:tagStyle="data.badge"
:data="item"
:titleColor="data.fields.name?.color"
:subTitleColor="data.fields.introduction.color"
:topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom"
:titleWidth="330 - marginLeft - marginRight"
@click="sheep.$router.go('/pages/goods/point', { id: item.activityId })"
@getHeight="calculateGoodsColumn($event, 'right')"
>
<!-- 购买按钮 -->
<template v-slot:cart>
<button class="ss-reset-button cart-btn" :style="[buyStyle]">
{{ btnBuy.type === 'text' ? btnBuy.text : '' }}
</button>
</template>
</s-goods-column>
</view>
</view>
</view>
</view>
</template>
<script setup>
/**
* 商品卡片
*/
import { computed, onMounted, reactive, ref } from 'vue';
import sheep from '@/sheep';
import SpuApi from '@/sheep/api/product/spu';
import PointApi from '@/sheep/api/promotion/point';
import { PromotionActivityTypeEnum } from '@/sheep/util/const';
//
const LayoutTypeEnum = {
//
ONE_COL_BIG_IMG: 'oneColBigImg',
//
TWO_COL: 'twoCol',
//
ONE_COL_SMALL_IMG: 'oneColSmallImg',
};
const state = reactive({
spuList: [],
leftSpuList: [],
rightSpuList: [],
});
const props = defineProps({
data: {
type: Object,
default() {},
},
styles: {
type: Object,
default() {},
},
});
const { layoutType, btnBuy, activityIds } = props.data || {};
const { marginLeft, marginRight } = props.styles || {};
//
const buyStyle = computed(() => {
if (btnBuy.type === 'text') {
// 线
return {
background: `linear-gradient(to right, ${btnBuy.bgBeginColor}, ${btnBuy.bgEndColor})`,
};
}
if (btnBuy.type === 'img') {
//
return {
width: '54rpx',
height: '54rpx',
background: `url(${sheep.$url.cdn(btnBuy.imgUrl)}) no-repeat`,
backgroundSize: '100% 100%',
};
}
});
//region
//
let count = 0;
//
let leftHeight = 0;
//
let rightHeight = 0;
/**
* 计算商品在左列还是右列
* @param height 商品的高度
* @param where 添加到哪一列
*/
function calculateGoodsColumn(height = 0, where = 'left') {
//
if (!state.spuList[count]) return;
//
if (where === 'left') leftHeight += height;
if (where === 'right') rightHeight += height;
//
if (leftHeight <= rightHeight) {
state.leftSpuList.push(state.spuList[count]);
} else {
state.rightSpuList.push(state.spuList[count]);
}
//
count++;
}
//endregion
/**
* 根据商品编号列表获取商品列表
* @param ids 商品编号列表
* @return {Promise<undefined>} 商品列表
*/
async function getPointActivityDetailList(ids) {
const { data } = await PointApi.getPointActivityListByIds(ids);
return data;
}
/**
* 根据商品编号获取商品详情
* @param ids 商品编号列表
* @return {Promise<undefined>} 商品列表
*/
async function getSpuDetail(ids) {
const { data: spu } = await SpuApi.getSpuDetail(ids);
return spu;
}
//
onMounted(async () => {
//
const activityList = await getPointActivityDetailList(activityIds.join(','));
// SPUspuList
for (const activity of activityList) {
state.spuList.push(await getSpuDetail(activity.spuId));
}
//
activityList.forEach((activity) => {
// spu
const spu = state.spuList.find((spu) => activity.spuId === spu.id);
if (spu) {
spu.pointStock = activity.stock
spu.pointTotalStock = activity.totalStock
spu.point = activity.point
spu.pointPrice = activity.price
// ID
spu.activityId = activity.id;
//
spu.activityType = PromotionActivityTypeEnum.POINT.type;
}
});
//
if (layoutType === LayoutTypeEnum.TWO_COL) {
//
calculateGoodsColumn();
}
});
</script>
<style lang="scss" scoped>
.goods-md-wrap {
width: 100%;
}
.goods-list-box {
width: 50%;
box-sizing: border-box;
.left-list {
&:nth-last-child(1) {
margin-bottom: 0 !important;
}
}
.right-list {
&:nth-last-child(1) {
margin-bottom: 0 !important;
}
}
}
.goods-box {
&:nth-last-of-type(1) {
margin-bottom: 0 !important;
}
}
.goods-md-box,
.goods-sl-box,
.goods-lg-box {
position: relative;
.cart-btn {
position: absolute;
bottom: 18rpx;
right: 20rpx;
z-index: 11;
height: 50rpx;
line-height: 50rpx;
padding: 0 20rpx;
border-radius: 25rpx;
font-size: 24rpx;
color: #fff;
}
}
</style>

View File

@ -1,8 +1,39 @@
<!-- 装修组件 - 秒杀 -->
<template>
<view>
<view class="new-class">
<!-- 标题栏 -->
<view class="menu-list-wrap">
<uni-list :border="true">
<uni-list-item showArrow clickable @tap="sheep.$router.go('/pages/activity/seckill/list')">
<template v-slot:header>
<view class="ss-flex ss-col-center">
<div class="wh">
<img class="new-text1"
src="https://zysc.fjptzykj.com:3000/shangcheng/cb995c399d784c08e27d8f56b0a63ace2d13af3a1ee6aba5a2da71868dc4cf00.png" />
<span class="new-text">限时秒杀</span>
</div>
<!-- <image class="list-icon" src="https://zysc.fjptzykj.com:3000/shangcheng/1bd7faadbb3c319c6ad303edc23ecbf12162b8ac22e2c8058b3914397d9dd226.png"
mode="aspectFit"></image> -->
<view style="color: rgba(255, 51, 35, 1); font-size:15px;"
class="title-text ss-flex ss-row-center ss-col-center ss-m-l-20">
<span class="time">{{ hours < 10 ? '0' + hours : hours }}</span>:
<span class="time">{{ minutes < 10 ? '0' + minutes : minutes }}</span>:
<span class="time">{{ seconds < 10 ? '0' + seconds : seconds }}</span>
</view>
</view>
</template>
<template v-slot:footer>
<view style="color: rgb(187, 187, 187);font-size:15px;"
class="notice-text ss-flex ss-row-center ss-col-center">
查看更多
</view>
</template>
</uni-list-item>
</uni-list>
</view>
<!-- 样式一三列 - 上图下文 -->
<view
<!-- <view
v-if="layoutType === 'threeCol'"
class="goods-sm-box ss-flex ss-flex-wrap"
:style="[{ margin: '-' + data.space + 'rpx' }]"
@ -33,9 +64,9 @@
"
></s-goods-column>
</view>
</view>
</view> -->
<!-- 样式二一列 - 左图右文 -->
<view class="goods-box" v-if="layoutType === 'oneCol'">
<!-- <view class="goods-box" v-if="layoutType === 'oneCol'">
<view
class="goods-list"
v-for="(product, index) in productList"
@ -65,6 +96,23 @@
</template>
</s-goods-column>
</view>
</view> -->
<view v-if="'threeCol' === 'threeCol'" class="goods-sm-box ss-flex ss-flex-wrap"
:style="[{ margin: '-' + data.space + 'rpx' }]">
<view v-for="product in productList" :key="product.id" class="goods-card-box" :style="[
{
padding: data.space + 'rpx',
},
]">
<s-goods-column class="goods-card" size="sm" :goodsFields="data.fields" :tagStyle="tagStyle"
:data="product" :titleColor="data.fields.name?.color" :topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom" @click="
sheep.$router.go('/pages/goods/seckill', {
id: product.activityId,
})
"></s-goods-column>
</view>
</view>
</view>
</template>
@ -75,7 +123,11 @@
*
* @property {Array} list 商品列表
*/
import { computed, onMounted, ref } from 'vue';
import {
computed,
onMounted,
ref
} from 'vue';
import sheep from '@/sheep';
import SeckillApi from '@/sheep/api/promotion/seckill';
import SpuApi from '@/sheep/api/product/spu';
@ -92,8 +144,16 @@
},
});
let { layoutType, tagStyle, btnBuy, space } = props.data;
let { marginLeft, marginRight } = props.styles;
let {
layoutType,
tagStyle,
btnBuy,
space
} = props.data;
let {
marginLeft,
marginRight
} = props.styles;
//
const buyStyle = computed(() => {
@ -114,26 +174,77 @@
});
//
const totalTime = ref(5 * 60 * 60); // 5
const hours = ref(5);
const minutes = ref(0);
const seconds = ref(0);
let intervalId = null;
const updateClock = () => {
if (totalTime.value > 0) {
const newHours = Math.floor(totalTime.value / 3600);
const newMinutes = Math.floor((totalTime.value % 3600) / 60);
const newSeconds = totalTime.value % 60;
hours.value = newHours;
minutes.value = newMinutes;
seconds.value = newSeconds;
totalTime.value--;
} else {
clearTimer();
alert('倒计时结束');
}
};
const startTimer = () => {
intervalId = setInterval(updateClock, 1000);
};
const clearTimer = () => {
clearInterval(intervalId);
};
const productList = ref([]);
//
onMounted(async () => {
startTimer();
// todo@owen Yudao
const { data: activity } = await SeckillApi.getSeckillActivity(props.data.activityId);
const { data: spu } = await SpuApi.getSpuDetail(activity.spuId);
productList.value = [spu];
// const { data: activity } = await SeckillApi.getSeckillActivity(props.data.activityId);
// const { data: spu } = await SpuApi.getSpuDetail(activity.spuId);
const data = await SpuApi.getSpuSeckilllist();
console.log(data,"datadatadatadatadatadatadatadata")
productList.value = data.data;
});
// onBeforeUnmount(() => {
// clearTimer();
// });
</script>
<style lang="scss" scoped>
.time {
width: 20px;
height: 20px;
background: rgba(255, 237, 238, 1);
color: rgba(255, 51, 35, 1);
text-align: center;
padding: 0 3px;
}
:deep(.uni-border-bottom) {
height: 0;
}
.header-box {
height: 100rpx;
}
.goods-list {
position: relative;
&:nth-last-child(1) {
margin-bottom: 0 !important;
}
.cart-btn {
position: absolute;
bottom: 10rpx;
@ -147,9 +258,11 @@
color: #fff;
}
}
.goods-sm-box {
margin: 0 auto;
box-sizing: border-box;
.goods-card-box {
flex-shrink: 0;
overflow: hidden;
@ -158,3 +271,113 @@
}
}
</style>
<style lang="scss">
:deep(.uni-list--border-bottom) {
height: 0 !important;
}
:deep(.container--right) {
padding-left: 5px !important;
}
.ss-col-center {
.list-icon {
position: relative;
width: 93px;
height: 40px;
padding-right: 10px;
&::after {
position: absolute;
content: '';
top: 50%;
right: 0;
width: 1px;
height: 57%;
border-right: 1px solid #ababab;
transform: translateY(-50%);
}
}
}
.notice-text {}
.menu-list-wrap {
::v-deep .uni-list {
background-color: transparent;
}
}
</style>
<style lang="scss" scoped>
.goods-list {
position: relative;
.cart-btn {
position: absolute;
bottom: 10rpx;
right: 20rpx;
z-index: 11;
height: 50rpx;
line-height: 50rpx;
padding: 0 20rpx;
border-radius: 25rpx;
font-size: 24rpx;
color: #fff;
}
}
.goods-list {
&:nth-last-of-type(1) {
margin-bottom: 0 !important;
}
}
.goods-sm-box {
margin: 0 auto;
box-sizing: border-box;
.goods-card-box {
flex-shrink: 0;
overflow: hidden;
width: 33.3%;
box-sizing: border-box;
}
}
.new-class {
background: white;
border-radius: 8px;
}
:deep(.sm-goods-card) {
background: transparent;
}
.wh {
position: relative;
padding-right: 10px;
display: flex;
align-items: center;
.new-text1 {
width: 30px;
height:30px;
}
.new-text {
font-weight: 700;
}
}
.wh::after {
position: absolute;
content: "";
top: 50%;
right: 0;
width: 1px;
height: 57%;
border-right: 1px solid #ababab;
transform: translateY(-50%);
}
</style>

View File

@ -319,7 +319,7 @@
font-size: 24rpx;
font-weight: 600;
margin-left: -50rpx;
background-image: v-bind(headerBg);
background-image: url('@/static/images/groupon-btn-long.png');
background-repeat: no-repeat;
background-size: 100% 100%;
color: #ffffff;

View File

@ -103,7 +103,7 @@
showAuthModal();
return;
}
console.log(props.shareInfo);
console.log(props.shareInfo,"props.shareInfo");
unref(SharePosterRef).getPoster();
state.showPosterModal = true;
};

View File

@ -57,9 +57,9 @@
const elStyles = {
background: `url(${sheep.$url.cdn(props.data.bgImgUrl)}) no-repeat top center / 100% auto`,
fontSize: `${props.data.titleSize}px`,
fontWeight: `${props.data.titleWeight}px`,
fontWeight: props.data.titleWeight,
};
console.log(elStyles,"elStyleselStyles")
//
const titleStyles = {
color: props.data.titleColor,

View File

@ -4,35 +4,32 @@
<view class="ss-flex ss-col-center ss-row-between ss-m-b-20">
<view class="left-box ss-flex ss-col-center ss-m-l-36">
<view class="avatar-box ss-m-r-24">
<image
class="avatar-img"
:src="
<image class="avatar-img" :src="
isLogin
? sheep.$url.cdn(userInfo.avatar)
: defaultAvatar
"
mode="aspectFill"
@tap="sheep.$router.go('/pages/user/info')"
></image>
" mode="aspectFill" @tap="sheep.$router.go('/pages/user/info')"></image>
</view>
<view>
<view class="nickname-box ss-flex ss-col-center">
<view class="nick-name ss-m-r-20">{{ userInfo?.nickname || nickname }}</view>
</view>
<view class="nickname-box ss-flex ss-col-center">
<view class="nick-name ss-m-r-20">{{ userInfo?.mobile || mobile }}</view>
</view>
</view>
</view>
<view class="right-box ss-m-r-52">
<button class="ss-reset-button" @tap="showShareModal">
<text class="sicon-qrcode"></text>
</button>
<!-- <view class="qiandao" @click="sheep.$router.go('/pages/app/sign');">
签到
</view> -->
</view>
</view>
<!-- 提示绑定手机号 先隐藏 yudao 需要再修改 -->
<view
class="bind-mobile-box ss-flex ss-row-between ss-col-center"
v-if="isLogin && !userInfo.mobile"
>
<view class="bind-mobile-box ss-flex ss-row-between ss-col-center" v-if="isLogin && !userInfo.mobile">
<view class="ss-flex">
<text class="cicon-mobile-o" />
<view class="mobile-title ss-m-l-20"> 点击绑定手机号确保账户安全 </view>
@ -59,9 +56,15 @@
*
*
*/
import { computed, reactive } from 'vue';
import {
computed,
reactive
} from 'vue';
import sheep from '@/sheep';
import { showShareModal, showAuthModal } from '@/sheep/hooks/useModal';
import {
showShareModal,
showAuthModal
} from '@/sheep/hooks/useModal';
//
const userInfo = computed(() => sheep.$store('user').userInfo);
@ -104,6 +107,17 @@
</script>
<style lang="scss" scoped>
.qiandao{
width: 50px;
height: 30px;
background: yellow;
text-align: center;
line-height: 30px;
font-weight: 700;
border-radius: 30px 0px 30px 30px;
font-size: 15px;
}
.ss-user-info-wrap {
box-sizing: border-box;

View File

@ -7,20 +7,13 @@
>
<view class="value-box ss-flex ss-col-bottom">
<view class="value-text ss-line-1">{{ fen2yuan(userWallet.balance) || '0.00' }}</view>
<view class="unit-text ss-m-l-6"></view>
<view class="unit-text ss-m-l-6">
<!-- -->
</view>
<view class="menu-title ss-m-t-28">账户余额</view>
</view>
<view
class="menu-item ss-flex-1 ss-flex-col ss-row-center ss-col-center"
@tap="sheep.$router.go('/pages/user/wallet/score')"
>
<view class="value-box ss-flex ss-col-bottom">
<view class="value-text">{{ userInfo.point || 0 }}</view>
<view class="unit-text ss-m-l-6"></view>
</view>
<view class="menu-title ss-m-t-28">积分</view>
<view class="menu-title ss-m-t-28">余额</view>
</view>
<view
class="menu-item ss-flex-1 ss-flex-col ss-row-center ss-col-center"
@tap="
@ -31,11 +24,25 @@
>
<view class="value-box ss-flex ss-col-bottom">
<view class="value-text">{{ numData.unusedCouponCount }}</view>
<view class="unit-text ss-m-l-6"></view>
<view class="unit-text ss-m-l-6">
<!-- -->
</view>
</view>
<view class="menu-title ss-m-t-28">优惠券</view>
</view>
<view
class="menu-item ss-flex-1 ss-flex-col ss-row-center ss-col-center"
@tap="sheep.$router.go('/pages/user/wallet/score')"
>
<view class="value-box ss-flex ss-col-bottom">
<view class="value-text">{{ userInfo.point || 0 }}</view>
<view class="unit-text ss-m-l-6">
<!-- -->
</view>
</view>
<view class="menu-title ss-m-t-28">积分</view>
</view>
<!-- <view
class="menu-item ss-flex-col ss-row-center ss-col-center menu-wallet"
@tap="sheep.$router.go('/pages/user/wallet/money')"
>
@ -45,7 +52,7 @@
mode="aspectFit"
/>
<view class="menu-title ss-m-t-30">我的钱包</view>
</view>
</view> -->
</view>
</template>
@ -75,7 +82,7 @@
.menu-title {
font-size: 24rpx;
line-height: 24rpx;
color: #333333;
color: white;
}
.item-icon {
@ -88,8 +95,9 @@
text-align: center;
.value-text {
font-size: 28rpx;
color: #000000;
font-size: 30rpx;
font-weight: 600;
color: white;
line-height: 28rpx;
vertical-align: text-bottom;
font-family: OPPOSANS;
@ -97,7 +105,7 @@
.unit-text {
font-size: 24rpx;
color: #343434;
color: white;
line-height: 24rpx;
}
}

View File

@ -164,10 +164,10 @@ const checkUpdate = async (silence = true) => {
// 获取订阅消息模板
async function getSubscribeTemplate() {
const { error, data } = await third.wechat.subscribeTemplate();
if (error === 0) {
subscribeEventList = data;
}
// const { error, data } = await third.wechat.subscribeTemplate();
// if (error === 0) {
// subscribeEventList = data;
// }
}
// 订阅消息

View File

@ -1,7 +1,7 @@
<template>
<view class="ui-coupon-wrap">
<!-- xs: 一行三个竖向 -->
<view
<!-- <view
v-if="props.size === 'xs'"
class="xs-coupon-card ss-flex ss-flex-col ss-row-between"
:style="[cardStyle]"
@ -23,10 +23,10 @@
<button class="ss-reset-button card-btn">{{ state.stateMap[props.state] }}</button>
</slot>
</view>
</view>
</view> -->
<!-- md: 一行两个横向 -->
<view
<!-- <view
v-if="props.size === 'md'"
class="md-coupon-card ss-flex ss-row-between"
:style="[cardStyle]"
@ -53,10 +53,10 @@
</button>
</slot>
</view>
</view>
</view> -->
<!-- lg: 一行一个横向 -->
<view
<!-- <view
v-if="props.size === 'lg'"
class="lg-coupon-card ss-flex ss-row-between"
:style="[cardStyle]"
@ -84,6 +84,37 @@
</slot>
<view class="surplus-text ss-m-t-24" v-if="props.surplus">仅剩{{ props.surplus }}</view>
</view>
</view> -->
<!-- @tap="
sheep.$router.go('/pages/coupon/detail', {
id: couponId,
})
" -->
<view
v-if="'md' === 'md'"
class=" md-coupon-card ss-flex ss-row-between"
:style="[cardStyle]"
@tap="
sheep.$router.go('/pages/coupon/list')
"
>
<view style="margin: 0 auto;" class="card-left ss-flex ss-flex-col ss-row-between ss-col-top">
<view class="face-value-box ss-flex ss-col-bottom ss-m-t-28">
<view class="value-text ss-m-r-4"><span style="font-size: 14px;">{{type === 'reduce' ?'¥':''}}</span><span style="font-size: 24px;">{{ type === 'reduce' ? Number(value) : Number(value/10) }}</span></view>
<view class="value-unit">{{ type === 'reduce' ? ' ' : '折' }}</view>
</view>
<view class="ss-m-b-28">
<view class="title-text ss-m-b-10">{{ props.title }}</view>
<view class="surplus-text" v-if="props.surplus">仅剩{{ props.surplus }}</view>
</view>
</view>
<view class="card-right ss-flex ss-row-center">
<slot name="btn">
<button class="ss-reset-button card-btn ss-flex ss-row-center ss-col-center">
<view class="btn-text">{{ state.stateMap[props.state] }}</view>
</button>
</slot>
</view>
</view>
</view>
</template>
@ -175,6 +206,7 @@
</script>
<style lang="scss" scoped>
// xs
.xs-coupon-card {
width: 227rpx;
@ -221,8 +253,8 @@
// md
.md-coupon-card {
width: 330rpx;
height: 168rpx;
width: 296rpx;
height: 74px;
border-radius: 10rpx;
overflow: hidden;

View File

@ -1,3 +1,36 @@
// ========== COMMON - 公共模块 ==========
/**
* 与后端Terminal枚举一一对应
*/
export const TerminalEnum = {
UNKNOWN: 0, // 未知, 目的:在无法解析到 terminal 时,使用它
WECHAT_MINI_PROGRAM: 10, //微信小程序
WECHAT_WAP: 11, // 微信公众号
H5: 20, // H5 网页
APP: 31, // 手机 App
};
/**
* uni-app 提供的平台转换为后端所需的 terminal值
*
* @return 终端
*/
export const getTerminal = () => {
const platformType = uni.getSystemInfoSync().uniPlatform;
// 与后端terminal枚举一一对应
switch (platformType) {
case 'app':
return TerminalEnum.APP;
case 'web':
return TerminalEnum.H5;
case 'mp-weixin':
return TerminalEnum.WECHAT_MINI_PROGRAM;
default:
return TerminalEnum.UNKNOWN;
}
};
// ========== MALL - 营销模块 ==========
import dayjs from 'dayjs';
@ -48,6 +81,7 @@ export const PromotionProductScopeEnum = {
},
};
// 时间段的状态枚举
export const TimeStatusEnum = {
WAIT_START: '即将开始',
@ -55,6 +89,37 @@ export const TimeStatusEnum = {
END: '已结束',
};
/**
* 微信小程序的订阅模版
*/
export const WxaSubscribeTemplate = {
TRADE_ORDER_DELIVERY: '订单发货通知',
PROMOTION_COMBINATION_SUCCESS: '拼团结果通知',
PAY_WALLET_RECHARGER_SUCCESS: '充值成功通知',
};
export const PromotionActivityTypeEnum = {
NORMAL: {
type: 0,
name: '普通',
},
SECKILL: {
type: 1,
name: '秒杀',
},
BARGAIN: {
type: 2,
name: '砍价',
},
COMBINATION: {
type: 3,
name: '拼团',
},
POINT: {
type: 4,
name: '积分商城',
},
};
export const getTimeStatusEnum = (startTime, endTime) => {
const now = dayjs();
if (now.isBefore(startTime)) {

BIN
static/images/dayu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 806 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 726 B

After

Width:  |  Height:  |  Size: 606 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 934 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 1004 B

BIN
static/images/order2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -86,7 +86,7 @@ $uni-border-color:#e5e5e5;
top: 0;
right: 0;
left: 0;
height: 1px;
// height: 1px;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
background-color: $uni-border-color;
@ -98,7 +98,7 @@ $uni-border-color:#e5e5e5;
bottom: 0;
right: 0;
left: 0;
height: 1px;
// height: 1px;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
background-color: $uni-border-color;

View File

@ -0,0 +1,14 @@
## 1.0.32023-11-25
修改:点击事件的返回参数
this.$emit('clickItem',item,index,this.items)
## 1.0.22023-11-18
修复:高度设置失效
## 1.0.12023-11-18
修复:在 vue2 中 class 调用方法不支持传参问题
## 1.0.02023-10-18
# 创建项目:个性化幻灯片
1. 支持放大动画;
2. 幻灯片点击事件;
3. 幻灯片动态定义;
4. 幻灯片数据多态,对象数组或字符串数组。

View File

@ -0,0 +1,147 @@
<template>
<swiper class="zmxy-slideshow swiper" circular :autoplay="autoplay" :vertical="vertical" :previous-margin="margin"
:next-margin="margin" :current="current" :interval="interval" :easing-function="easingFunction"
:style="'height:' + height" @change="swiperChange">
<swiper-item v-for="(item,index) in items" :key="index">
<view :class="'swiper-item '+(index == current ?'active':'')" @click="clickItem(item)">
<view class="yi sd">VIP{{item.level}}</view>
<view class="er sd">{{item.name}}</view>
<view class="san sd">再获得 {{item.experience}} 成长值升级为该等级</view>
<image class="swiper-item-image" :src="item.backgroundUrl||item" mode="aspectFill"></image>
<view v-if="item.title" class="swiper-item-title">
{{ item.title }}
</view>
</view>
</swiper-item>
</swiper>
</template>
<script>
export default {
name: 'zmxy-slideshow', //
data() {
return {
current: 0,
}
},
props: {
items: {
type: [Array, Object],
default: () => {
return [];
}
},
interval: {
type: [Number, String],
default: 5000
},
autoplay: {
type: Boolean,
default: true
},
vertical: {
type: Boolean,
default: false
},
margin: {
type: String,
default: '60rpx'
},
height: {
type: String,
default: '300rpx'
},
easingFunction: {
type: String,
default: 'easeInOutCubic'
},
},
mounted(){
console.log(this.items,"items")
// this.items = this.items.map(member => member.backgroundUrl)
},
methods: {
swiperChange(e) {
this.current = e.detail.current
},
clickItem(item) {
this.$emit('clickItem', item)
},
}
}
</script>
<style lang="scss">
.sd{
color:white;
position: absolute;
z-index: 22;
}
.yi{
top: 25px;
font-size: 26px;
left: 12px;
font-weight: 600;
}
.er{
top: 60px;
font-size: 13px;
left: 12px;
/* font-weight: 600;*/
}
.san{
bottom: 10px;
font-size: 13px;
left: 12px;
/* font-weight: 600;*/
}
.zmxy-slideshow {
width: 100%;
.swiper-item {
width: 100%;
height: 100%;
overflow: hidden;
border-radius: 5px;
position: relative;
display: flex;
align-items: center;
transform: scale(0.9, 0.80);
transition: all .6s;
.swiper-item-image {
width: 100%;
height: 100%;
border-radius: 6rpx;
}
.swiper-item-title {
position: absolute;
bottom: 0;
left: 0;
right: 0;
color: rgba(255, 255, 255, 0);
background: rgba(0, 0, 0, 0);
padding: 10rpx;
transition: color .6s, background .6s;
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
&.active {
transform: scale(1, 1);
.swiper-item-image {}
.swiper-item-title {
color: rgba(255, 255, 255, 1);
background: rgba(0, 0, 0, 0.5);
}
}
}
}
</style>

View File

@ -0,0 +1,85 @@
{
"id": "zmxy-slideshow",
"displayName": "zmxy-slideshow-个性化幻灯片",
"version": "1.0.3",
"description": "zmxy-slideshow-个性化幻灯片,常用于轮播图,广告播放",
"keywords": [
"幻灯片",
"轮播图",
"广告横幅",
"渐变",
"放大"
],
"repository": "",
"engines": {
"HBuilderX": "^3.8.0"
},
"dcloudext": {
"type": "component-vue",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"Vue": {
"vue2": "y",
"vue3": "y"
},
"App": {
"app-vue": "y",
"app-nvue": "n"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "n",
"QQ": "y",
"钉钉": "y",
"快手": "y",
"飞书": "n",
"京东": "n"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}

View File

@ -0,0 +1,65 @@
# zmxy-slideshow 幻灯片
> 该组件是对原生
> [swiper](https://uniapp.dcloud.net.cn/component/swiper.html)
> 进行封装,继承了原组件部分属性及功能。
## 属性说明
| 属性名 | 类型 | 默认值 | 说明 | 平台差异说明 |
|:-------------------:|:-----------:|:--------:|:----------------------------------------------------------------------------------------------------:|:------------------------------------------------:|
| autoplay | Boolean | true | 是否自动切换 | |
| interval | Number | 5000 | 自动切换时间间隔 | |
| vertical | Boolean | false | 滑动方向是否为纵向 | |
| margin | String | 60rpx | 前后边距,接受 px 和 rpx 值 | app-nvue、抖音小程序、飞书小程序不支持 |
| easing-function | String | default | 指定 swiper 切换缓动动画类型有效值default、linear、easeInCubic、easeOutCubic、easeInOutCubic | 微信小程序、快手小程序、京东小程序 |
| height | String | 300rpx | 组件整体高度,接受 px 和 rpx 值 | |
| items | Array | [] | 图片地址、标题、链接等数据组成的对象数组([{url,title,link,...},{url,title,link,...},...]),也支持字符串数组([url1,url2,url3,...] | |
| @clickItem | EventHandle | | 点击幻灯片触发 clickItem 事件item = {url,title,link,...} 或者 item = url |
### easing-function 属性
| 值 | 说明 |
|:---------------:|:-------:|
| default | 默认缓动函数 |
| linear | 线性动画 |
| easeInCubic | 缓入动画 |
| easeOutCubic | 缓出动画 |
| easeInOutCubic | 缓入缓出动画 |
### 案例代码
```vue
# 基础使用
<zmxy-slideshow :items="items"></zmxy-slideshow>
# 字符串数组,线性动画
<zmxy-slideshow :items="items2" easing-function="linear"></zmxy-slideshow>
```
```javascript
export default {
data() {
return {
items: [{
url: 'https://web-assets.dcloud.net.cn/unidoc/zh/shuijiao.jpg',
title: '内容标题',
}, {
url: 'https://web-assets.dcloud.net.cn/unidoc/zh/shuijiao.jpg',
title: '内容标题',
}, {
url: 'https://web-assets.dcloud.net.cn/unidoc/zh/shuijiao.jpg',
title: '内容标题',
}, ],
items2: [
'https://web-assets.dcloud.net.cn/unidoc/zh/shuijiao.jpg',
'https://web-assets.dcloud.net.cn/unidoc/zh/shuijiao.jpg',
'https://web-assets.dcloud.net.cn/unidoc/zh/shuijiao.jpg',
],
};
},
methods: {
clickItem(item) {
console.log(item);
}
}
}
```