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 # 后端接口 - 正式环境(通过 process.env.NODE_ENV 非 development
SHOPRO_BASE_URL = https://zysc.fjptzykj.com SHOPRO_BASE_URL = https://zysc.fjptzykj.com
#SHOPRO_BASE_URL = http://192.168.1.20:6127
# 后端接口 - 测试环境(通过 process.env.NODE_ENV = development # 后端接口 - 测试环境(通过 process.env.NODE_ENV = development
SHOPRO_DEV_BASE_URL = https://zysc.fjptzykj.com 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 SHOPRO_API_PATH = /app-api

View File

@ -20,6 +20,32 @@
"group": "商城" "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", "path": "pages/index/user",
"style": { "style": {
@ -120,11 +146,10 @@
} }
}, },
{ {
"path" : "pages/mulu/mulu", "path": "pages/mulu/mulu",
"style" : "style": {
{ "navigationBarTitleText": "详情",
"navigationBarTitleText" : "详情", "enablePullDownRefresh": true,
"enablePullDownRefresh" : true,
"navigationStyle": "default" "navigationStyle": "default"
} }
} }
@ -165,6 +190,28 @@
"group": "商品" "group": "商品"
} }
}, },
{
"path": "point",
"style": {
"navigationBarTitleText": "积分商品"
},
"meta": {
"sync": true,
"title": "积分商品",
"group": "商品"
}
},
{
"path": "sales",
"style": {
"navigationBarTitleText": "促销商品"
},
"meta": {
"sync": true,
"title": "促销商品",
"group": "商品"
}
},
{ {
"path": "list", "path": "list",
"style": { "style": {
@ -238,16 +285,16 @@
"title": "申请售后" "title": "申请售后"
} }
}, },
{ {
"path": "aftersale/return-delivery", "path": "aftersale/return-delivery",
"style": { "style": {
"navigationBarTitleText": "退货物流" "navigationBarTitleText": "退货物流"
}, },
"meta": { "meta": {
"auth": true, "auth": true,
"title": "退货物流" "title": "退货物流"
} }
}, },
{ {
"path": "aftersale/list", "path": "aftersale/list",
"style": { "style": {
@ -306,6 +353,18 @@
"group": "用户中心" "group": "用户中心"
} }
}, },
{
"path": "user_vip/index",
"style": {
"navigationBarTitleText": "会员中心"
},
"meta": {
"auth": true,
"sync": true,
"title": "会员中心",
"group": "用户中心"
}
},
{ {
"path": "goods-collect", "path": "goods-collect",
"style": { "style": {
@ -352,6 +411,16 @@
"title": "编辑地址" "title": "编辑地址"
} }
}, },
{
"path": "goods_details_store/index",
"style": {
"navigationBarTitleText": "门店管理"
},
"meta": {
"auth": true,
"title": "门店管理"
}
},
{ {
"path": "wallet/money", "path": "wallet/money",
"style": { "style": {
@ -462,17 +531,17 @@
"group": "分销商城" "group": "分销商城"
} }
}, { }, {
"path": "withdraw", "path": "withdraw",
"style": { "style": {
"navigationBarTitleText": "申请提现" "navigationBarTitleText": "申请提现"
}, },
"meta": { "meta": {
"auth": true, "auth": true,
"sync": true, "sync": true,
"title": "申请提现", "title": "申请提现",
"group": "分销商城" "group": "分销商城"
} }
} }
] ]
}, },
{ {

View File

@ -1,516 +1,531 @@
<!-- 拼团订单的详情 --> <!-- 拼团订单的详情 -->
<template> <template>
<s-layout <s-layout title="拼团详情" class="detail-wrap" :navbar="state.data && !state.loading ? 'inner' : 'normal'">
title="拼团详情" <!-- :onShareAppMessage="shareInfo" -->
class="detail-wrap" <view v-if="state.loading"></view>
:navbar="state.data && !state.loading ? 'inner' : 'normal'" <view v-if="state.data && !state.loading">
:onShareAppMessage="shareInfo" <!-- 团长信息 + 活动信息 -->
> <view class="recharge-box" v-if="state.data.headRecord" :style="[
<view v-if="state.loading"></view>
<view v-if="state.data && !state.loading">
<!-- 团长信息 + 活动信息 -->
<view
class="recharge-box"
v-if="state.data.headRecord"
:style="[
{ {
marginTop: '-' + Number(statusBarHeight + 88) + 'rpx', marginTop: '-' + Number(statusBarHeight + 88) + 'rpx',
paddingTop: Number(statusBarHeight + 108) + 'rpx', paddingTop: Number(statusBarHeight + 108) + 'rpx',
}, },
]" ]">
> <s-goods-item class="goods-box" :img="state.data.headRecord.picUrl"
<s-goods-item :title="state.data.headRecord.spuName" :price="state.data.headRecord.combinationPrice"
class="goods-box" priceColor="#E1212B" @tap="
:img="state.data.headRecord.picUrl"
:title="state.data.headRecord.spuName"
:price="state.data.headRecord.combinationPrice"
priceColor="#E1212B"
@tap="
sheep.$router.go('/pages/goods/groupon', { sheep.$router.go('/pages/goods/groupon', {
id: state.data.headRecord.activityId, id: state.data.headRecord.activityId,
}) })
" " :style="[{ top: Number(statusBarHeight + 108) + 'rpx' }]">
:style="[{ top: Number(statusBarHeight + 108) + 'rpx' }]" <template #groupon>
> <view class="ss-flex">
<template #groupon> <view class="sales-title">{{ state.data.headRecord.userSize }}人团</view>
<view class="ss-flex"> <view class="num-title ss-m-l-20">已拼{{ state.data.headRecord.userCount }}</view>
<view class="sales-title">{{ state.data.headRecord.userSize }}人团</view> </view>
<view class="num-title ss-m-l-20">已拼{{ state.data.headRecord.userCount }}</view> </template>
</view> </s-goods-item>
</template> </view>
</s-goods-item> <image class="image" mode="aspectFill"
</view> 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">
<view v-if="state.data.orderId">
<view class="countdown-title ss-flex">
<text class="cicon-check-round" />
恭喜您~拼团成功
</view>
</view>
<view v-else>
<view class="countdown-title ss-flex">
<text class="cicon-info" />
抱歉~该团已满员
</view>
</view>
</view>
<view class="countdown-box detail-card ss-p-t-44 ss-flex-col ss-col-center"> <!-- 情况二拼团失败 -->
<!-- 情况一拼团成功 --> <view v-if="state.data.headRecord.status === 2">
<view v-if="state.data.headRecord.status === 1"> <view class="countdown-title ss-flex">
<view v-if="state.data.orderId"> <text class="cicon-info"></text>
<view class="countdown-title ss-flex"> {{ state.data.orderId ? '拼团超时,已自动退款' : '该团已解散' }}
<text class="cicon-check-round" /> </view>
恭喜您~拼团成功 </view>
</view>
</view>
<view v-else>
<view class="countdown-title ss-flex">
<text class="cicon-info" />
抱歉~该团已满员
</view>
</view>
</view>
<!-- 情况二拼团失败 --> <!-- 情况三拼团进行中 -->
<view v-if="state.data.headRecord.status === 2"> <view v-if="state.data.headRecord.status === 0">
<view class="countdown-title ss-flex"> <view v-if="state.data.headRecord.expireTime <= new Date().getTime()">
<text class="cicon-info"></text> <view class="countdown-title ss-flex">
{{ state.data.orderId ? '拼团超时,已自动退款' : '该团已解散' }} <text class="cicon-info"></text>
</view> 拼团已结束,请关注下次活动
</view> </view>
</view>
<view class="countdown-title ss-flex" v-else>
还差
<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>
<view class="ss-m-x-4">:</view>
<view class="countdown-num ss-flex ss-row-center">
{{ endTime.m }}
</view>
<view class="ss-m-x-4">:</view>
<view class="countdown-num ss-flex ss-row-center">
{{ endTime.s }}
</view>
</view>
</view>
</view>
<!-- 情况三拼团进行中 --> <!-- 拼团的记录列表展示每个参团人 -->
<view v-if="state.data.headRecord.status === 0"> <view class="ss-m-t-60 ss-flex ss-flex-wrap ss-row-center">
<view v-if="state.data.headRecord.expireTime <= new Date().getTime()"> <!-- 团长 -->
<view class="countdown-title ss-flex"> <view class="header-avatar ss-m-r-24 ss-m-b-20">
<text class="cicon-info"></text> <image :src="sheep.$url.cdn(state.data.headRecord.avatar)" class="avatar-img"></image>
拼团已结束,请关注下次活动 <view class="header-tag ss-flex ss-col-center ss-row-center">团长</view>
</view> </view>
</view> <!-- 团员 -->
<view class="countdown-title ss-flex" v-else> <view class="header-avatar ss-m-r-24 ss-m-b-20" v-for="item in state.data.memberRecords"
还差 :key="item.id">
<view class="num" <image :src="sheep.$url.cdn(item.avatar)" class="avatar-img"></image>
>{{ state.data.headRecord.userSize - state.data.headRecord.userCount }}</view <view class="header-tag ss-flex ss-col-center ss-row-center" v-if="item.is_leader == '1'">
> 团长
拼团成功 </view>
<view class="ss-flex countdown-time"> </view>
<view class="countdown-h ss-flex ss-row-center">{{ endTime.h }}</view> <!-- 还有几个坑位 -->
<view class="ss-m-x-4">:</view> <view class="default-avatar ss-m-r-24 ss-m-b-20" v-for="item in state.remainNumber" :key="item">
<view class="countdown-num ss-flex ss-row-center"> <image :src="sheep.$url.static('/static/img/shop/avatar/unknown.png')" class="avatar-img">
{{ endTime.m }} </image>
</view> </view>
<view class="ss-m-x-4">:</view> </view>
<view class="countdown-num ss-flex ss-row-center"> </view>
{{ endTime.s }}
</view>
</view>
</view>
</view>
<!-- 拼团的记录列表展示每个参团人 --> <!-- 情况一拼团成功情况二拼团失败 -->
<view class="ss-m-t-60 ss-flex ss-flex-wrap ss-row-center"> <view v-if="state.data.headRecord.status === 1 || state.data.headRecord.status === 2"
<!-- 团长 --> class="ss-m-t-40 ss-flex ss-row-center">
<view class="header-avatar ss-m-r-24 ss-m-b-20"> <button class="ss-reset-button order-btn" v-if="state.data.orderId" @tap="onDetail(state.data.orderId)">
<image :src="sheep.$url.cdn(state.data.headRecord.avatar)" class="avatar-img"></image> 查看订单
<view class="header-tag ss-flex ss-col-center ss-row-center">团长</view> </button>
</view> <button class="ss-reset-button join-btn" v-else @tap="onCreateGroupon"> 我要开团 </button>
<!-- 团员 --> </view>
<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>
</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>
</view>
</view>
<!-- 情况一拼团成功情况二拼团失败 --> <!-- 情况三拼团进行中查看订单或参加或邀请好友或参加 -->
<view <view v-if="state.data.headRecord.status === 0" class="ss-m-t-40 ss-flex ss-row-center">
v-if="state.data.headRecord.status === 1 || state.data.headRecord.status === 2" <view v-if="state.data.headRecord.expireTime <= new Date().getTime()">
class="ss-m-t-40 ss-flex ss-row-center" <button class="ss-reset-button join-btn" v-if="state.data.orderId"
> @tap="onDetail(state.data.orderId)">
<button 查看订单
class="ss-reset-button order-btn" </button>
v-if="state.data.orderId" <button class="ss-reset-button disabled-btn" v-else disabled @tap="onDetail(state.data.orderId)">
@tap="onDetail(state.data.orderId)" 去参团
> </button>
查看订单 </view>
</button> <view v-else class="ss-flex ss-row-center">
<button class="ss-reset-button join-btn" v-else @tap="onCreateGroupon"> 我要开团 </button> <view v-if="state.data.orderId">
</view> <button class="ss-reset-button join-btn" :disabled="endTime.ms <= 0" @tap="onShare">
邀请好友来拼团
</button>
</view>
<view v-else>
<button class="ss-reset-button join-btn" :disabled="endTime.ms <= 0" @tap="onJoinGroupon()">
立即参团
</button>
</view>
</view>
</view>
<!-- 情况三拼团进行中查看订单或参加或邀请好友或参加 --> <!-- TODO 芋艿这里暂时没接入 -->
<view v-if="state.data.headRecord.status === 0" class="ss-m-t-40 ss-flex ss-row-center"> <s-select-groupon-sku :show="state.showSelectSku" :goodsInfo="state.goodsInfo"
<view v-if="state.data.headRecord.expireTime <= new Date().getTime()"> :grouponAction="state.grouponAction" :grouponNum="state.grouponNum" @buy="onBuy" @change="onSkuChange"
<button @close="state.showSelectSku = false" />
class="ss-reset-button join-btn" </view>
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>
</view>
<view v-else class="ss-flex ss-row-center">
<view v-if="state.data.orderId">
<button class="ss-reset-button join-btn" :disabled="endTime.ms <= 0" @tap="onShare">
邀请好友来拼团
</button>
</view>
<view v-else>
<button
class="ss-reset-button join-btn"
:disabled="endTime.ms <= 0"
@tap="onJoinGroupon()"
>
立即参团
</button>
</view>
</view>
</view>
<!-- TODO 芋艿这里暂时没接入 --> <s-empty v-if="!state.data && !state.loading" icon="/static/goods-empty.png" />
<view v-if="state.data.goods"> </s-layout>
<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>
</view>
<s-empty v-if="!state.data && !state.loading" icon="/static/goods-empty.png" />
</s-layout>
</template> </template>
<script setup> <script setup>
import { computed, reactive } from 'vue'; import {
import sheep from '@/sheep'; computed,
import { onLoad } from '@dcloudio/uni-app'; reactive
import { useDurationTime } from '@/sheep/hooks/useGoods'; } from 'vue';
import { showShareModal } from '@/sheep/hooks/useModal'; import sheep from '@/sheep';
import { isEmpty } from 'lodash'; import {
import CombinationApi from '@/sheep/api/promotion/combination'; 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 headerBg = sheep.$url.css('/static/img/shop/user/withdraw_bg.png');
const statusBarHeight = sheep.$platform.device.statusBarHeight * 2; const statusBarHeight = sheep.$platform.device.statusBarHeight * 2;
const state = reactive({ const state = reactive({
data: {}, // data: {
loading: true, goods: true
grouponAction: 'create', }, //
showSelectSku: false, loading: true,
grouponNum: 0, grouponAction: 'create',
number: 0, showSelectSku: false,
activity: {}, grouponNum: 0,
combinationHeadId: null, // number: 0,
}); activity: {},
combinationHeadId: null, //
goodsInfo: {}, //
goodsId: '',
skeletonLoading: false,
goodsSwiper: [], //
});
// todo // todo
const shareInfo = computed(() => { const shareInfo = computed(() => {
if (isEmpty(state.data)) return {}; if (isEmpty(state.data)) return {};
return sheep.$platform.share.getShareInfo( return sheep.$platform.share.getShareInfo({
{ title: state.data.headRecord.spuName,
title: state.data.headRecord.spuName, image: sheep.$url.cdn(state.data.headRecord.picUrl),
image: sheep.$url.cdn(state.data.headRecord.picUrl), desc: state.data.goods?.subtitle,
desc: state.data.goods?.subtitle, params: {
params: { page: '5',
page: '5', query: state.data.id,
query: state.data.id, },
}, }, {
}, type: 'groupon', //
{ title: state.data.headRecord.spuName, //
type: 'groupon', // image: sheep.$url.cdn(state.data.headRecord.picUrl), //
title: state.data.headRecord.spuName, // price: state.data.goods?.price, //
image: sheep.$url.cdn(state.data.headRecord.picUrl), // original_price: state.data.goods?.original_price, //
price: state.data.goods?.price, // }, );
original_price: state.data.goods?.original_price, // });
},
);
});
// //
function onDetail(orderId) { function onDetail(orderId) {
sheep.$router.go('/pages/order/detail', { sheep.$router.go('/pages/order/detail', {
id: orderId, id: orderId,
}); });
} }
// TODO // TODO
function onCreateGroupon() { function onCreateGroupon() {
state.grouponAction = 'create'; state.grouponAction = 'create';
state.grouponId = 0; state.grouponId = 0;
state.showSelectSku = true; state.showSelectSku = true;
} }
// TODO // TODO
function onSkuChange(e) { function onSkuChange(e) {
state.selectedSkuPrice = e; state.selectedSkuPrice = e;
} }
// TODO // TODO
function onJoinGroupon() { function onJoinGroupon() {
state.grouponAction = 'join'; state.grouponAction = 'join';
state.grouponId = state.data.activityId; state.grouponId = state.activityId;
state.combinationHeadId = state.data.id; state.combinationHeadId = state.id;
state.grouponNum = state.data.num; state.grouponNum = state.userSize;
state.showSelectSku = true; state.showSelectSku = true;
} }
// TODO // TODO
function onBuy(sku) { function onBuy(sku) {
sheep.$router.go('/pages/order/confirm', { sheep.$router.go('/pages/order/confirm', {
data: JSON.stringify({ data: JSON.stringify({
order_type: 'goods', order_type: 'goods',
combinationActivityId: state.data.activity.id, combinationActivityId: state.grouponId,
combinationHeadId: state.combinationHeadId, combinationHeadId: state.combinationHeadId,
items: [ items: [{
{ skuId: sku.id,
skuId: sku.id, count: sku.count,
count: sku.count, }, ],
}, }),
], });
}), }
});
}
const endTime = computed(() => { //
return useDurationTime(state.data.headRecord.expireTime); 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(() => {
async function getGrouponDetail(id) { return useDurationTime(state.data.headRecord.expireTime);
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( async function getGrouponDetail(id) {
data.headRecord.activityId, const {
); code,
state.activity = activity; data
} else { } = await CombinationApi.getCombinationRecordDetail(id);
state.data = null; if (code === 0) {
} state.data = data;
state.loading = false; const remainNumber = Number(state.data.headRecord.userSize - state.data.headRecord.userCount);
} state.remainNumber = remainNumber > 0 ? remainNumber : 0;
function onShare() { //
showShareModal(); const {
} data: activity
} = await CombinationApi.getCombinationActivity(
data.headRecord.activityId,
);
state.activity = activity;
} else {
state.data = null;
}
state.loading = false;
}
onLoad((options) => { function onShare() {
getGrouponDetail(options.id); showShareModal();
}); }
onLoad((options) => {
getGrouponDetail(options.id);
//
if (!options.id) {
state.goodsInfo = null;
return;
}
state.grouponId = options.id;
loadActiv();
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.recharge-box { .image {
position: relative; display: block;
margin-bottom: 120rpx; margin: 0 auto;
background: v-bind(headerBg) center/750rpx 100% no-repeat, width: 100%;
linear-gradient(115deg, #f44739 0%, #ff6600 100%); height: 154px;
border-radius: 0 0 5% 5%; }
height: 100rpx;
.goods-box { .recharge-box {
width: 710rpx; position: relative;
border-radius: 20rpx; margin-bottom: 120rpx;
position: absolute; background: v-bind(headerBg) center/750rpx 100% no-repeat,
left: 20rpx; linear-gradient(115deg, #f44739 0%, #ff6600 100%);
box-sizing: border-box; border-radius: 0 0 5% 5%;
} height: 100rpx;
.sales-title { .goods-box {
height: 32rpx; width: 710rpx;
background: rgba(#ffe0e2, 0.29); border-radius: 20rpx;
border-radius: 16rpx; position: absolute;
font-size: 24rpx; left: 20rpx;
font-weight: 400; box-sizing: border-box;
padding: 6rpx 20rpx; }
color: #f7979c;
}
.num-title { .sales-title {
font-size: 24rpx; height: 32rpx;
font-weight: 400; background: rgba(#ffe0e2, 0.29);
color: #999999; border-radius: 16rpx;
} font-size: 24rpx;
} font-weight: 400;
padding: 6rpx 20rpx;
color: #f7979c;
}
.countdown-time { .num-title {
font-size: 26rpx; font-size: 24rpx;
font-weight: 500; font-weight: 400;
color: #383a46; color: #999999;
.countdown-h { }
font-size: 24rpx; }
font-family: OPPOSANS;
font-weight: 500;
color: #ffffff;
padding: 0 4rpx;
margin-left: 16rpx;
height: 40rpx;
background: linear-gradient(90deg, #ff6000 0%, #fe832a 100%);
border-radius: 6rpx;
}
.countdown-num {
font-size: 24rpx;
font-family: OPPOSANS;
font-weight: 500;
color: #ffffff;
width: 40rpx;
height: 40rpx;
background: linear-gradient(90deg, #ff6000 0%, #fe832a 100%);
border-radius: 6rpx;
}
}
.countdown-box { .countdown-time {
// height: 364rpx; font-size: 26rpx;
background: #ffffff; font-weight: 500;
border-radius: 10rpx; color: #383a46;
box-sizing: border-box;
.countdown-title { .countdown-h {
font-size: 28rpx; font-size: 24rpx;
font-weight: 500; font-family: OPPOSANS;
color: #333333; font-weight: 500;
color: #ffffff;
padding: 0 4rpx;
margin-left: 16rpx;
height: 40rpx;
background: linear-gradient(90deg, #ff6000 0%, #fe832a 100%);
border-radius: 6rpx;
}
.cicon-check-round { .countdown-num {
color: #42b111; font-size: 24rpx;
margin-right: 24rpx; font-family: OPPOSANS;
} font-weight: 500;
color: #ffffff;
width: 40rpx;
height: 40rpx;
background: linear-gradient(90deg, #ff6000 0%, #fe832a 100%);
border-radius: 6rpx;
}
}
.cicon-info { .countdown-box {
color: #d71e08; // height: 364rpx;
margin-right: 24rpx; background: #ffffff;
} border-radius: 10rpx;
box-sizing: border-box;
.num { .countdown-title {
color: #ff6000; font-size: 28rpx;
} font-weight: 500;
} color: #333333;
.header-avatar { .cicon-check-round {
width: 86rpx; color: #42b111;
height: 86rpx; margin-right: 24rpx;
background: #ececec; }
border-radius: 50%;
border: 4rpx solid #edc36c;
position: relative;
box-sizing: border-box;
.avatar-img { .cicon-info {
width: 100%; color: #d71e08;
height: 100%; margin-right: 24rpx;
border-radius: 50%; }
}
.header-tag { .num {
width: 72rpx; color: #ff6000;
height: 36rpx; }
font-size: 24rpx; }
line-height: nor;
background: linear-gradient(132deg, #f3dfb1, #f3dfb1, #ecbe60);
border-radius: 16rpx;
position: absolute;
left: 4rpx;
top: -36rpx;
}
}
.default-avatar {
width: 86rpx;
height: 86rpx;
background: #ececec;
border-radius: 50%;
.avatar-img {
width: 100%;
height: 100%;
border-radius: 50%;
}
}
.user-avatar { .header-avatar {
width: 86rpx; width: 86rpx;
height: 86rpx; height: 86rpx;
background: #ececec; background: #ececec;
border-radius: 50%; border-radius: 50%;
} border: 4rpx solid #edc36c;
} position: relative;
.order-btn { box-sizing: border-box;
width: 668rpx;
height: 70rpx;
border: 2rpx solid #dfdfdf;
border-radius: 35rpx;
color: #999999;
font-weight: 500;
font-size: 26rpx;
line-height: normal;
}
.disabled-btn { .avatar-img {
width: 668rpx; width: 100%;
height: 70rpx; height: 100%;
background: #dddddd; border-radius: 50%;
border-radius: 35rpx; }
color: #999999;
font-weight: 500;
font-size: 28rpx;
line-height: normal;
}
.join-btn { .header-tag {
width: 668rpx; width: 72rpx;
height: 70rpx; height: 36rpx;
background: linear-gradient(90deg, #ff6000 0%, #fe832a 100%); font-size: 24rpx;
box-shadow: 0px 8rpx 6rpx 0px rgba(255, 104, 4, 0.22); line-height: nor;
border-radius: 35rpx; background: linear-gradient(132deg, #f3dfb1, #f3dfb1, #ecbe60);
color: #fff; border-radius: 16rpx;
font-weight: 500; position: absolute;
font-size: 28rpx; left: 4rpx;
line-height: normal; top: -36rpx;
} }
}
.detail-cell-wrap { .default-avatar {
width: 100%; width: 86rpx;
padding: 10rpx 20rpx; height: 86rpx;
box-sizing: border-box; background: #ececec;
border-top: 2rpx solid #dfdfdf; border-radius: 50%;
background-color: #fff;
// min-height: 60rpx;
.label-text { .avatar-img {
font-size: 28rpx; width: 100%;
font-weight: 400; height: 100%;
} border-radius: 50%;
}
}
.cell-content { .user-avatar {
font-size: 28rpx; width: 86rpx;
font-weight: 500; height: 86rpx;
color: $dark-6; background: #ececec;
} border-radius: 50%;
}
}
.right-forwrad-icon { .order-btn {
font-size: 28rpx; width: 668rpx;
font-weight: 500; height: 70rpx;
color: $dark-9; border: 2rpx solid #dfdfdf;
} border-radius: 35rpx;
} color: #999999;
font-weight: 500;
font-size: 26rpx;
line-height: normal;
}
.disabled-btn {
width: 668rpx;
height: 70rpx;
background: #dddddd;
border-radius: 35rpx;
color: #999999;
font-weight: 500;
font-size: 28rpx;
line-height: normal;
}
.join-btn {
width: 668rpx;
height: 70rpx;
background: linear-gradient(90deg, #ff6000 0%, #fe832a 100%);
box-shadow: 0px 8rpx 6rpx 0px rgba(255, 104, 4, 0.22);
border-radius: 35rpx;
color: #fff;
font-weight: 500;
font-size: 28rpx;
line-height: normal;
}
.detail-cell-wrap {
width: 100%;
padding: 10rpx 20rpx;
box-sizing: border-box;
border-top: 2rpx solid #dfdfdf;
background-color: #fff;
// min-height: 60rpx;
.label-text {
font-size: 28rpx;
font-weight: 400;
}
.cell-content {
font-size: 28rpx;
font-weight: 500;
color: $dark-6;
}
.right-forwrad-icon {
font-size: 28rpx;
font-weight: 500;
color: $dark-9;
}
}
</style> </style>

View File

@ -119,7 +119,7 @@
width: 100%; width: 100%;
height: 458rpx; height: 458rpx;
margin-top: -88rpx; margin-top: -88rpx;
background: v-bind(headerBg) no-repeat; background: url('https://zysc.fjptzykj.com:3000/shangcheng/fea9ad54f32d4705a633874efd534e70e507030ea5a7604b0110fdf7292f1f4d.png');
background-size: 100% 100%; background-size: 100% 100%;
} }
.list-content { .list-content {
@ -203,9 +203,11 @@
} }
} }
.scroll-box { .scroll-box {
margin-top: 13px;
height: 900rpx; height: 900rpx;
.goods-box { .goods-box {
position: relative; position: relative;
padding: 0 10px;
.cart-btn { .cart-btn {
position: absolute; position: absolute;
bottom: 10rpx; 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"> <view class="img-wrap">
<image <image
class="notice-img" class="notice-img"
:src="sheep.$url.static('/static/img/shop/commission/forbidden.png')" src="https://zysc.fjptzykj.com:3000/shangcheng/a999baebceb39e97a8ff11c547b41bf1e78109d81532eafbd858544f86e5e159.png"
mode="aspectFill" mode="aspectFill"
/> />
</view> </view>

View File

@ -34,7 +34,7 @@
height: 192rpx; height: 192rpx;
margin: -88rpx 20rpx 0 20rpx; margin: -88rpx 20rpx 0 20rpx;
padding-top: 88rpx; 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%; background-size: 100% 100%;
.head-img-box { .head-img-box {

View File

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

View File

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

View File

@ -351,7 +351,7 @@
width: 750rpx; width: 750rpx;
z-index: 3; z-index: 3;
position: relative; 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)); linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
background-size: 750rpx 100%; background-size: 750rpx 100%;

View File

@ -88,12 +88,12 @@
// //
.seckill-box { .seckill-box {
background: v-bind(seckillBg) no-repeat; background: url('https://zysc.fjptzykj.com:3000/shangcheng/0796100444273e747b7afc5778081bf8a1f8373707822cccc272cc205e7ad0f3.png') no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
} }
.groupon-box { .groupon-box {
background: v-bind(grouponBg) no-repeat; background: url('https://zysc.fjptzykj.com:3000/shangcheng/0796100444273e747b7afc5778081bf8a1f8373707822cccc272cc205e7ad0f3.png') no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
} }
</style> </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' }]" :style="[{ height: pageHeight + 'px' }]"
v-if="state.categoryList?.length" v-if="state.categoryList?.length"
> >
<image <!-- <image
v-if="state.categoryList[state.activeMenu].picUrl" v-if="state.categoryList[state.activeMenu].picUrl"
class="banner-img" class="banner-img"
:src="sheep.$url.cdn(state.categoryList[state.activeMenu].picUrl)" :src="sheep.$url.cdn(state.categoryList[state.activeMenu].picUrl)"
mode="widthFix" mode="widthFix"
/> /> -->
<first-one v-if="state.style === 'first_one'" :pagination="state.pagination" /> <first-one v-if="state.style === 'first_one'" :pagination="state.pagination" />
<first-two v-if="state.style === 'first_two'" :pagination="state.pagination" /> <first-two v-if="state.style === 'first_two'" :pagination="state.pagination" />
<second-one <second-one

View File

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

View File

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

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>
<view <view
class="order-item ss-flex ss-col-center ss-row-between" 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="item-title">积分抵扣</view>
<view class="ss-flex ss-col-center"> <view class="ss-flex ss-col-center">
@ -52,7 +52,7 @@
class="score-img" class="score-img"
/> />
<text class="item-value ss-m-r-24"> <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> </text>
<checkbox-group @change="changeIntegral"> <checkbox-group @change="changeIntegral">
<checkbox :checked='state.pointStatus' :disabled="!state.orderInfo.totalPoint || state.orderInfo.totalPoint <= 0" /> <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 { .store-cent-left {
//width: 45%; width: 177px;
flex: 2; // flex: 2;
} }
.store-img { .store-img {
flex: 1; // flex: 1;
width: 120rpx; width: 120rpx;
height: 120rpx; height: 120rpx;
border-radius: 6rpx; 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,41 +1,86 @@
import request from '@/sheep/request'; import request from '@/sheep/request';
const SpuApi = { const SpuApi = {
// 获得商品 SPU 列表 // 获得商品促销列表
getSpuListByIds: (ids) => { getSpusales: (params) => {
return request({ return request({
url: '/product/spu/list-by-ids', url:'/product/spu/get-recommend-page',
method: 'GET', method: 'GET',
params: { ids }, params,
custom: { custom: {
showLoading: false, showLoading: false,
showError: false, showError: false,
}, },
}); });
}, },
// 获得商品 SPU 分页 // 获得商品 SPU 列表
getSpuPage: (params) => { getSpuListByIds: (ids) => {
return request({ return request({
url: '/product/spu/page', url: '/product/spu/list-by-ids',
method: 'GET', method: 'GET',
params, params: {
custom: { ids
showLoading: false, },
showError: false, custom: {
}, showLoading: false,
}); showError: false,
}, },
// 查询商品 });
getSpuDetail: (id) => { },
return request({ // 获得商品 SPU 分页
url: '/product/spu/get-detail', getSpuPage: (params) => {
method: 'GET', return request({
params: { id }, url: '/product/spu/page',
custom: { method: 'GET',
showLoading: false, params,
showError: false, custom: {
}, showLoading: false,
}); showError: false,
}, },
});
},
// 查询商品
getSpuDetail: (id) => {
return request({
url: '/product/spu/get-detail',
method: 'GET',
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,
},
});
},
}; };
export default SpuApi; export default SpuApi;

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', method: 'get',
}); });
}, },
// 获得自提门店列表
getDeliveryPickUpStoreList: () => {
return request({
url: `/trade/delivery/pick-up-store/list`,
method: 'get',
});
},
}; };
export default DeliveryApi; export default DeliveryApi;

View File

@ -40,6 +40,8 @@
<s-groupon-block v-if="type === 'PromotionCombination'" :data="data" :styles="styles" /> <s-groupon-block v-if="type === 'PromotionCombination'" :data="data" :styles="styles" />
<!-- 营销组件秒杀 --> <!-- 营销组件秒杀 -->
<s-seckill-block v-if="type === 'PromotionSeckill'" :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" /> <s-live-block v-if="type === 'MpLive'" :data="data" :styles="styles" />
<!-- 营销组件优惠券 --> <!-- 营销组件优惠券 -->
@ -66,6 +68,16 @@
<!-- 用户组件用户卡片 --> <!-- 用户组件用户卡片 -->
<s-user-card v-if="type === 'UserCard'" /> <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" /> <s-order-card v-if="type === 'UserOrder'" :data="data" />
<!-- 用户组件用户资产 --> <!-- 用户组件用户资产 -->
@ -118,6 +130,35 @@
</script> </script>
<style scoped lang="scss"> <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 { .floxt {
width: 100%; width: 100%;
.addClass { .addClass {

View File

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

View File

@ -40,7 +40,7 @@
:class="isDisable ? 'disabled-color' : 'subtitle-color'" :class="isDisable ? 'disabled-color' : 'subtitle-color'"
v-if="data.validityType === 2" v-if="data.validityType === 2"
> >
有效期领取后 {{ data.fixedEndTerm }} 天内可用 有效期领取后{{ data.fixedStartTerm }}天开始至第{{ data.fixedEndTerm }}天内有效
</view> </view>
<view class="sellby-text" :class="isDisable ? 'disabled-color' : 'subtitle-color'" v-else> <view class="sellby-text" :class="isDisable ? 'disabled-color' : 'subtitle-color'" v-else>
有效期: {{ sheep.$helper.timeFormat(data.validStartTime, 'yyyy-mm-dd') }} 有效期: {{ 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 { .tag-icon {
width: 72rpx; width: 72rpx;
height: 44rpx; height: 44rpx;
border-radius:8px;
} }
} }
.seckill-tag { .seckill-tag {
@ -580,11 +581,14 @@
// width: 100%; // width: 100%;
background-color: $white; background-color: $white;
position: relative; position: relative;
padding: 0 10px;
padding-top: 10px;
.sm-img-box { .sm-img-box {
// width: 228rpx; // width: 228rpx;
width: 100%; width: 100%;
height: 208rpx; height: 208rpx;
border-radius:8px;
} }
.sm-goods-content { .sm-goods-content {
padding: 20rpx 16rpx; padding: 20rpx 16rpx;
@ -604,7 +608,8 @@
// md // md
.md-goods-card { .md-goods-card {
overflow: hidden; overflow: hidden;
width: 100%; width: auto;
padding: 10px 10px;
position: relative; position: relative;
z-index: 1; z-index: 1;
background-color: $white; background-color: $white;

View File

@ -1,154 +1,260 @@
<!-- 装修组件 - 拼团 --> <!-- 装修组件 - 拼团 -->
<template> <template>
<view> <view class="new-class">
<view <!-- 标题栏 -->
v-if="layoutType === 'threeCol'" <view class="menu-list-wrap">
class="goods-sm-box ss-flex ss-flex-wrap" <uni-list :border="true">
:style="[{ margin: '-' + data.space + 'rpx' }]" <uni-list-item showArrow clickable
> @tap="sheep.$router.go('/pages/activity/groupon/list')">
<view <template v-slot:header>
v-for="product in productList" <view>
:key="product.id" <view class="wh">
class="goods-card-box" <img class="new-text1"
:style="[ 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', padding: data.space + 'rpx',
}, },
]" ]">
> <s-goods-column class="goods-card" size="sm" :goodsFields="data.fields" :tagStyle="tagStyle"
<s-goods-column :data="product" :titleColor="data.fields.name?.color" :topRadius="data.borderRadiusTop"
class="goods-card" :bottomRadius="data.borderRadiusBottom" @click="
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', { sheep.$router.go('/pages/goods/groupon', {
id: props.data.activityId, id: props.data.activityId,
}) })
" "></s-goods-column>
></s-goods-column> </view>
</view> </view> -->
</view> <!-- 样式2 一行一个 图片左 文案右 -->
<!-- 样式2 一行一个 图片左 文案右 --> <!-- <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" :key="index"
<view :style="[{ marginBottom: space + 'px' }]">
class="goods-list" <s-goods-column class="goods-card" size="lg" :goodsFields="data.fields" :tagStyle="tagStyle"
v-for="(product, index) in productList" :data="product" :titleColor="data.fields.name?.color"
:key="index" :subTitleColor="data.fields.introduction?.color" :topRadius="data.borderRadiusTop"
:style="[{ marginBottom: space + 'px' }]" :bottomRadius="data.borderRadiusBottom" @click="
>
<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', { sheep.$router.go('/pages/goods/groupon', {
id: props.data.activityId, id: props.data.activityId,
}) })
" ">
> <template v-slot:cart>
<template v-slot:cart> <button class="ss-reset-button cart-btn" :style="[buyStyle]">
<button class="ss-reset-button cart-btn" :style="[buyStyle]"> {{ btnBuy?.type === 'text' ? btnBuy.text : '' }}
{{ btnBuy?.type === 'text' ? btnBuy.text : '' }} </button>
</button> </template>
</template> </s-goods-column>
</s-goods-column> </view>
</view> </view> -->
</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> </template>
<script setup> <script setup>
/** /**
* 拼团 * 拼团
*/ */
import { computed, onMounted, ref } from 'vue'; import {
import sheep from '@/sheep'; computed,
import SpuApi from '@/sheep/api/product/spu'; onMounted,
import CombinationApi from '@/sheep/api/promotion/combination'; ref
} from 'vue';
import sheep from '@/sheep';
import SpuApi from '@/sheep/api/product/spu';
import CombinationApi from '@/sheep/api/promotion/combination';
// //
const props = defineProps({ const props = defineProps({
data: { data: {
type: Object, type: Object,
default() {}, default () {},
}, },
styles: { styles: {
type: Object, type: Object,
default() {}, default () {},
}, },
}); });
let { layoutType, tagStyle, btnBuy, space } = props.data; let {
let { marginLeft, marginRight } = props.styles; layoutType,
tagStyle,
btnBuy,
space
} = props.data;
let {
marginLeft,
marginRight
} = props.styles;
// //
const buyStyle = computed(() => { const buyStyle = computed(() => {
let btnBuy = props.data.btnBuy; let btnBuy = props.data.btnBuy;
if (btnBuy?.type === 'text') { if (btnBuy?.type === 'text') {
return { return {
background: `linear-gradient(to right, ${btnBuy.bgBeginColor}, ${btnBuy.bgEndColor})`, background: `linear-gradient(to right, ${btnBuy.bgBeginColor}, ${btnBuy.bgEndColor})`,
}; };
} }
if (btnBuy?.type === 'img') { if (btnBuy?.type === 'img') {
return { return {
width: '54rpx', width: '54rpx',
height: '54rpx', height: '54rpx',
background: `url(${sheep.$url.cdn(btnBuy.imgUrl)}) no-repeat`, background: `url(${sheep.$url.cdn(btnBuy.imgUrl)}) no-repeat`,
backgroundSize: '100% 100%', backgroundSize: '100% 100%',
}; };
} }
}); });
const productList = ref([]); const productList = ref([]);
onMounted(async () => { onMounted(async () => {
// todo@owen Yudao // todo@owen Yudao
const { data: activity } = await CombinationApi.getCombinationActivity(props.data.activityId); const {
const { data: spu } = await SpuApi.getSpuDetail(activity.spuId); data: activity
productList.value = [spu]; } = await CombinationApi.getCombinationActivity(props.data.activityId);
}); const ss = await SpuApi.getSpulist();
console.log(ss, "getSpuListByIds")
productList.value = ss.data;
});
</script> </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;
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 {
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 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;
}
}
</style> </style>

View File

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

View File

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

View File

@ -1,66 +1,72 @@
<!-- 装修基础组件列表导航 --> <!-- 装修基础组件列表导航 -->
<template> <template>
<view class="menu-list-wrap"> <view class="menu-list-wrap">
<uni-list :border="true"> <uni-list :border="true">
<uni-list-item <uni-list-item v-for="(item, index) in data.list" :key="index" showArrow clickable
v-for="(item, index) in data.list" @tap="sheep.$router.go(item.url)">
:key="index" <template v-slot:header>
showArrow <view class="ss-flex ss-col-center">
clickable <image v-if="item.iconUrl" class="list-icon" :src="sheep.$url.cdn(item.iconUrl)"
@tap="sheep.$router.go(item.url)" mode="aspectFit"></image>
> <view class="title-text ss-flex ss-row-center ss-col-center ss-m-l-20"
<template v-slot:header> :style="[{ color: item.titleColor }]">
<view class="ss-flex ss-col-center"> {{ item.title }}
<image </view>
v-if="item.iconUrl" </view>
class="list-icon" </template>
:src="sheep.$url.cdn(item.iconUrl)" <template v-slot:footer>
mode="aspectFit" <view class="notice-text ss-flex ss-row-center ss-col-center"
></image> :style="[{ color: item.subtitleColor }]">
<view {{ item.subtitle }}
class="title-text ss-flex ss-row-center ss-col-center ss-m-l-20" </view>
:style="[{ color: item.titleColor }]" </template>
> </uni-list-item>
{{ item.title }} </uni-list>
</view> </view>
</view>
</template>
<template v-slot:footer>
<view
class="notice-text ss-flex ss-row-center ss-col-center"
:style="[{ color: item.subtitleColor }]"
>
{{ item.subtitle }}
</view>
</template>
</uni-list-item>
</uni-list>
</view>
</template> </template>
<script setup> <script setup>
/** /**
* cell * cell
*/ */
import sheep from '@/sheep'; import sheep from '@/sheep';
const props = defineProps({ const props = defineProps({
data: { data: {
type: Object, type: Object,
default: () => ({}), default: () => ({}),
}, },
}); });
</script> </script>
<style lang="scss"> <style lang="scss">
.list-icon { :deep(.container--right){
width: 20px; padding-left: 5px !important;
height: 20px; }
} .ss-col-center{
.notice-text { .list-icon {
} position: relative;
.menu-list-wrap { width: 100px;
::v-deep .uni-list { height: 40px;
background-color: transparent; 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>

View File

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

View File

@ -1,8 +1,14 @@
<!-- 装修用户组件用户订单 --> <!-- 装修用户组件用户订单 -->
<template> <template>
<view> <view style="background:white;">
<view class="title"> <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>
<view class="ss-order-menu-wrap ss-flex ss-col-center"> <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 == 3" class="item-icon" :src="imag3" mode="aspectFit" />
<image v-if="index == 4" class="item-icon" :src="imag4" mode="aspectFit" /> <image v-if="index == 4" class="item-icon" :src="imag4" mode="aspectFit" />
</uni-badge> </uni-badge>
<view class="menu-title ss-m-t-28">{{ item.title }}</view> <view class="menu-title">{{ item.title }}</view>
</view> </view>
</view> </view>
</view> </view>
@ -27,7 +33,7 @@
import imag1 from '@/static/images/no_take.png' import imag1 from '@/static/images/no_take.png'
import imag2 from '@/static/images/no_comment.png' import imag2 from '@/static/images/no_comment.png'
import imag3 from '@/static/images/order.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', type: 'unpaid',
count: 'unpaidCount', count: 'unpaidCount',
}, },
{
title: '待发货',
value: '2',
icon: '/static/img/shop/order/no_take.png',
path: '/pages/order/list',
type: 'take',
count: 'undeliveredCount',
},
{ {
title: '待收货', title: '待收货',
value: '3', value: '3',
@ -61,32 +75,51 @@
count: 'uncommentedCount', count: 'uncommentedCount',
}, },
{ {
title: '售后', title: '退款/售后',
value: '0', value: '0',
icon: '/static/img/shop/order/change_order.png', icon: '/static/img/shop/order/change_order.png',
path: '/pages/order/aftersale/list', path: '/pages/order/aftersale/list',
type: 'aftersale', type: 'aftersale',
count: 'afterSaleCount', count: 'afterSaleCount',
}, }
{ // ,
title: '全部订单', // {
value: '0', // title: '',
icon: '/static/img/shop/order/all_order.png', // value: '0',
path: '/pages/order/list', // icon: '/static/img/shop/order/all_order.png',
}, // path: '/pages/order/list',
// }
]; ];
const numData = computed(() => sheep.$store('user').numData); const numData = computed(() => sheep.$store('user').numData);
console.log(numData,'numData')
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.title { .title {
padding: 10px 20px; padding: 10px 10px;
height: 20px; height: 20px;
line-height: 20px; line-height: 20px;
font-size: 16px; font-size: 16px;
font-weight: 600; 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 { .ss-order-menu-wrap {
@ -99,6 +132,7 @@
font-size: 24rpx; font-size: 24rpx;
line-height: 24rpx; line-height: 24rpx;
color: #333333; color: #333333;
margin-top:14rpx;
} }
.item-icon { .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> <template>
<view> <view class="new-class">
<!-- 样式一三列 - 上图下文 --> <!-- 标题栏 -->
<view <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
v-if="layoutType === 'threeCol'" v-if="layoutType === 'threeCol'"
class="goods-sm-box ss-flex ss-flex-wrap" class="goods-sm-box ss-flex ss-flex-wrap"
:style="[{ margin: '-' + data.space + 'rpx' }]" :style="[{ margin: '-' + data.space + 'rpx' }]"
@ -33,9 +64,9 @@
" "
></s-goods-column> ></s-goods-column>
</view> </view>
</view> </view> -->
<!-- 样式二一列 - 左图右文 --> <!-- 样式二一列 - 左图右文 -->
<view class="goods-box" v-if="layoutType === 'oneCol'"> <!-- <view class="goods-box" v-if="layoutType === 'oneCol'">
<view <view
class="goods-list" class="goods-list"
v-for="(product, index) in productList" v-for="(product, index) in productList"
@ -65,96 +96,288 @@
</template> </template>
</s-goods-column> </s-goods-column>
</view> </view>
</view> </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> </template>
<script setup> <script setup>
/** /**
* 秒杀商品列表 * 秒杀商品列表
* *
* @property {Array} list 商品列表 * @property {Array} list 商品列表
*/ */
import { computed, onMounted, ref } from 'vue'; import {
import sheep from '@/sheep'; computed,
import SeckillApi from '@/sheep/api/promotion/seckill'; onMounted,
import SpuApi from '@/sheep/api/product/spu'; ref
} from 'vue';
import sheep from '@/sheep';
import SeckillApi from '@/sheep/api/promotion/seckill';
import SpuApi from '@/sheep/api/product/spu';
// //
const props = defineProps({ const props = defineProps({
data: { data: {
type: Object, type: Object,
default() {}, default () {},
}, },
styles: { styles: {
type: Object, type: Object,
default() {}, default () {},
}, },
}); });
let { layoutType, tagStyle, btnBuy, space } = props.data; let {
let { marginLeft, marginRight } = props.styles; layoutType,
tagStyle,
btnBuy,
space
} = props.data;
let {
marginLeft,
marginRight
} = props.styles;
// //
const buyStyle = computed(() => { const buyStyle = computed(() => {
let btnBuy = props.data.btnBuy; let btnBuy = props.data.btnBuy;
if (btnBuy?.type === 'text') { if (btnBuy?.type === 'text') {
return { return {
background: `linear-gradient(to right, ${btnBuy.bgBeginColor}, ${btnBuy.bgEndColor})`, background: `linear-gradient(to right, ${btnBuy.bgBeginColor}, ${btnBuy.bgEndColor})`,
}; };
} }
if (btnBuy?.type === 'img') { if (btnBuy?.type === 'img') {
return { return {
width: '54rpx', width: '54rpx',
height: '54rpx', height: '54rpx',
background: `url(${sheep.$url.cdn(btnBuy.imgUrl)}) no-repeat`, background: `url(${sheep.$url.cdn(btnBuy.imgUrl)}) no-repeat`,
backgroundSize: '100% 100%', backgroundSize: '100% 100%',
}; };
} }
}); });
// //
const productList = ref([]); const totalTime = ref(5 * 60 * 60); // 5
// const hours = ref(5);
onMounted(async () => { const minutes = ref(0);
// todo@owen Yudao const seconds = ref(0);
const { data: activity } = await SeckillApi.getSeckillActivity(props.data.activityId); let intervalId = null;
const { data: spu } = await SpuApi.getSpuDetail(activity.spuId);
productList.value = [spu]; 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);
const data = await SpuApi.getSpuSeckilllist();
console.log(data,"datadatadatadatadatadatadatadata")
productList.value = data.data;
});
// onBeforeUnmount(() => {
// clearTimer();
// });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.header-box { .time {
height: 100rpx; width: 20px;
} height: 20px;
background: rgba(255, 237, 238, 1);
color: rgba(255, 51, 35, 1);
text-align: center;
padding: 0 3px;
}
.goods-list { :deep(.uni-border-bottom) {
position: relative; height: 0;
&:nth-last-child(1) { }
margin-bottom: 0 !important;
} .header-box {
.cart-btn { height: 100rpx;
position: absolute; }
bottom: 10rpx;
right: 20rpx; .goods-list {
z-index: 11; position: relative;
height: 50rpx;
line-height: 50rpx; &:nth-last-child(1) {
padding: 0 20rpx; margin-bottom: 0 !important;
border-radius: 25rpx; }
font-size: 24rpx;
color: #fff; .cart-btn {
} position: absolute;
} bottom: 10rpx;
.goods-sm-box { right: 20rpx;
margin: 0 auto; z-index: 11;
box-sizing: border-box; height: 50rpx;
.goods-card-box { line-height: 50rpx;
flex-shrink: 0; padding: 0 20rpx;
overflow: hidden; border-radius: 25rpx;
width: 33.3%; font-size: 24rpx;
box-sizing: border-box; color: #fff;
} }
} }
.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;
}
}
</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> </style>

View File

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

View File

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

View File

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

View File

@ -1,168 +1,182 @@
<!-- 装修用户组件用户卡片 --> <!-- 装修用户组件用户卡片 -->
<template> <template>
<view class="ss-user-info-wrap ss-p-t-50"> <view class="ss-user-info-wrap ss-p-t-50">
<view class="ss-flex ss-col-center ss-row-between ss-m-b-20"> <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="left-box ss-flex ss-col-center ss-m-l-36">
<view class="avatar-box ss-m-r-24"> <view class="avatar-box ss-m-r-24">
<image <image class="avatar-img" :src="
class="avatar-img"
:src="
isLogin isLogin
? sheep.$url.cdn(userInfo.avatar) ? sheep.$url.cdn(userInfo.avatar)
: defaultAvatar : defaultAvatar
" " mode="aspectFill" @tap="sheep.$router.go('/pages/user/info')"></image>
mode="aspectFill" </view>
@tap="sheep.$router.go('/pages/user/info')" <view>
></image> <view class="nickname-box ss-flex ss-col-center">
</view> <view class="nick-name ss-m-r-20">{{ userInfo?.nickname || nickname }}</view>
<view> </view>
<view class="nickname-box ss-flex ss-col-center"> <view class="nickname-box ss-flex ss-col-center">
<view class="nick-name ss-m-r-20">{{ userInfo?.nickname || nickname }}</view> <view class="nick-name ss-m-r-20">{{ userInfo?.mobile || mobile }}</view>
</view> </view>
</view> </view>
</view> </view>
<view class="right-box ss-m-r-52"> <view class="right-box ss-m-r-52">
<button class="ss-reset-button" @tap="showShareModal"> <button class="ss-reset-button" @tap="showShareModal">
<text class="sicon-qrcode"></text> <text class="sicon-qrcode"></text>
</button> </button>
</view> <!-- <view class="qiandao" @click="sheep.$router.go('/pages/app/sign');">
</view> 签到
</view> -->
<!-- 提示绑定手机号 先隐藏 yudao 需要再修改 --> </view>
<view </view>
class="bind-mobile-box ss-flex ss-row-between ss-col-center" <!-- 提示绑定手机号 先隐藏 yudao 需要再修改 -->
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">
<view class="ss-flex"> <text class="cicon-mobile-o" />
<text class="cicon-mobile-o" /> <view class="mobile-title ss-m-l-20"> 点击绑定手机号确保账户安全 </view>
<view class="mobile-title ss-m-l-20"> 点击绑定手机号确保账户安全 </view> </view>
</view> <button class="ss-reset-button bind-btn" @tap="onBind">去绑定</button>
<button class="ss-reset-button bind-btn" @tap="onBind">去绑定</button> </view>
</view> </view>
</view>
</template> </template>
<script setup> <script setup>
// 使 import // 使 import
import defaultAvatar from '@/static/images/default_avatar.png'; import defaultAvatar from '@/static/images/default_avatar.png';
/** /**
* 用户卡片 * 用户卡片
* *
* @property {Number} leftSpace - 容器左间距 * @property {Number} leftSpace - 容器左间距
* @property {Number} rightSpace - 容器右间距 * @property {Number} rightSpace - 容器右间距
* *
* @property {String} avatar - 头像 * @property {String} avatar - 头像
* @property {String} nickname - 昵称 * @property {String} nickname - 昵称
* @property {String} vip - 等级 * @property {String} vip - 等级
* @property {String} collectNum - 收藏数 * @property {String} collectNum - 收藏数
* @property {String} likeNum - 点赞数 * @property {String} likeNum - 点赞数
* *
* *
*/ */
import { computed, reactive } from 'vue'; import {
import sheep from '@/sheep'; computed,
import { showShareModal, showAuthModal } from '@/sheep/hooks/useModal'; reactive
} from 'vue';
import sheep from '@/sheep';
import {
showShareModal,
showAuthModal
} from '@/sheep/hooks/useModal';
// //
const userInfo = computed(() => sheep.$store('user').userInfo); const userInfo = computed(() => sheep.$store('user').userInfo);
console.log('用户信息', userInfo); console.log('用户信息', userInfo);
// //
const isLogin = computed(() => sheep.$store('user').isLogin); const isLogin = computed(() => sheep.$store('user').isLogin);
// //
const props = defineProps({ const props = defineProps({
background: { background: {
type: String, type: String,
default: '', default: '',
}, },
// //
avatar: { avatar: {
type: String, type: String,
default: '', default: '',
}, },
nickname: { nickname: {
type: String, type: String,
default: '请先登录', default: '请先登录',
}, },
vip: { vip: {
type: [String, Number], type: [String, Number],
default: '1', default: '1',
}, },
collectNum: { collectNum: {
type: [String, Number], type: [String, Number],
default: '1', default: '1',
}, },
likeNum: { likeNum: {
type: [String, Number], type: [String, Number],
default: '1', default: '1',
}, },
}); });
function onBind() { function onBind() {
showAuthModal('changeMobile'); showAuthModal('changeMobile');
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.ss-user-info-wrap { .qiandao{
box-sizing: border-box; width: 50px;
height: 30px;
background: yellow;
text-align: center;
line-height: 30px;
font-weight: 700;
border-radius: 30px 0px 30px 30px;
font-size: 15px;
}
.avatar-box { .ss-user-info-wrap {
width: 100rpx; box-sizing: border-box;
height: 100rpx;
border-radius: 50%;
overflow: hidden;
.avatar-img { .avatar-box {
width: 100%; width: 100rpx;
height: 100%; height: 100rpx;
} border-radius: 50%;
} overflow: hidden;
.nick-name { .avatar-img {
font-size: 34rpx; width: 100%;
font-weight: 400; height: 100%;
color: white; }
line-height: normal; }
}
.vip-img { .nick-name {
width: 30rpx; font-size: 34rpx;
height: 30rpx; font-weight: 400;
} color: white;
line-height: normal;
}
.sicon-qrcode { .vip-img {
font-size: 40rpx; width: 30rpx;
} height: 30rpx;
} }
.bind-mobile-box { .sicon-qrcode {
width: 100%; font-size: 40rpx;
height: 84rpx; }
padding: 0 34rpx 0 44rpx; }
box-sizing: border-box;
background: #ffffff;
box-shadow: 0px -8rpx 9rpx 0px rgba(#e0e0e0, 0.3);
.cicon-mobile-o { .bind-mobile-box {
font-size: 30rpx; width: 100%;
color: #ff690d; height: 84rpx;
} padding: 0 34rpx 0 44rpx;
box-sizing: border-box;
background: #ffffff;
box-shadow: 0px -8rpx 9rpx 0px rgba(#e0e0e0, 0.3);
.mobile-title { .cicon-mobile-o {
font-size: 24rpx; font-size: 30rpx;
font-weight: 500; color: #ff690d;
color: #ff690d; }
}
.bind-btn { .mobile-title {
width: 100rpx; font-size: 24rpx;
height: 50rpx; font-weight: 500;
background: #ff6100; color: #ff690d;
border-radius: 25rpx; }
font-size: 24rpx;
font-weight: 500; .bind-btn {
color: #ffffff; width: 100rpx;
} height: 50rpx;
} background: #ff6100;
border-radius: 25rpx;
font-size: 24rpx;
font-weight: 500;
color: #ffffff;
}
}
</style> </style>

View File

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

View File

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

View File

@ -1,7 +1,7 @@
<template> <template>
<view class="ui-coupon-wrap"> <view class="ui-coupon-wrap">
<!-- xs: 一行三个竖向 --> <!-- xs: 一行三个竖向 -->
<view <!-- <view
v-if="props.size === 'xs'" v-if="props.size === 'xs'"
class="xs-coupon-card ss-flex ss-flex-col ss-row-between" class="xs-coupon-card ss-flex ss-flex-col ss-row-between"
:style="[cardStyle]" :style="[cardStyle]"
@ -23,10 +23,10 @@
<button class="ss-reset-button card-btn">{{ state.stateMap[props.state] }}</button> <button class="ss-reset-button card-btn">{{ state.stateMap[props.state] }}</button>
</slot> </slot>
</view> </view>
</view> </view> -->
<!-- md: 一行两个横向 --> <!-- md: 一行两个横向 -->
<view <!-- <view
v-if="props.size === 'md'" v-if="props.size === 'md'"
class="md-coupon-card ss-flex ss-row-between" class="md-coupon-card ss-flex ss-row-between"
:style="[cardStyle]" :style="[cardStyle]"
@ -53,10 +53,10 @@
</button> </button>
</slot> </slot>
</view> </view>
</view> </view> -->
<!-- lg: 一行一个横向 --> <!-- lg: 一行一个横向 -->
<view <!-- <view
v-if="props.size === 'lg'" v-if="props.size === 'lg'"
class="lg-coupon-card ss-flex ss-row-between" class="lg-coupon-card ss-flex ss-row-between"
:style="[cardStyle]" :style="[cardStyle]"
@ -84,7 +84,38 @@
</slot> </slot>
<view class="surplus-text ss-m-t-24" v-if="props.surplus">仅剩{{ props.surplus }}</view> <view class="surplus-text ss-m-t-24" v-if="props.surplus">仅剩{{ props.surplus }}</view>
</view> </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> </view>
</template> </template>
@ -175,6 +206,7 @@
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
// xs // xs
.xs-coupon-card { .xs-coupon-card {
width: 227rpx; width: 227rpx;
@ -221,8 +253,8 @@
// md // md
.md-coupon-card { .md-coupon-card {
width: 330rpx; width: 296rpx;
height: 168rpx; height: 74px;
border-radius: 10rpx; border-radius: 10rpx;
overflow: hidden; 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 - 营销模块 ========== // ========== MALL - 营销模块 ==========
import dayjs from 'dayjs'; import dayjs from 'dayjs';
@ -48,6 +81,7 @@ export const PromotionProductScopeEnum = {
}, },
}; };
// 时间段的状态枚举 // 时间段的状态枚举
export const TimeStatusEnum = { export const TimeStatusEnum = {
WAIT_START: '即将开始', WAIT_START: '即将开始',
@ -55,6 +89,37 @@ export const TimeStatusEnum = {
END: '已结束', 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) => { export const getTimeStatusEnum = (startTime, endTime) => {
const now = dayjs(); const now = dayjs();
if (now.isBefore(startTime)) { 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; top: 0;
right: 0; right: 0;
left: 0; left: 0;
height: 1px; // height: 1px;
-webkit-transform: scaleY(0.5); -webkit-transform: scaleY(0.5);
transform: scaleY(0.5); transform: scaleY(0.5);
background-color: $uni-border-color; background-color: $uni-border-color;
@ -98,7 +98,7 @@ $uni-border-color:#e5e5e5;
bottom: 0; bottom: 0;
right: 0; right: 0;
left: 0; left: 0;
height: 1px; // height: 1px;
-webkit-transform: scaleY(0.5); -webkit-transform: scaleY(0.5);
transform: scaleY(0.5); transform: scaleY(0.5);
background-color: $uni-border-color; 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);
}
}
}
```