# Conflicts:
#	pages/goods/index.vue
#	pages/order/addressSelection.vue
#	pages/order/confirm.vue
#	sheep/components/s-goods-column/s-goods-column.vue
pull/102/MERGE
YunaiV 2024-09-16 08:24:54 +08:00
commit f03fcf1373
72 changed files with 3179 additions and 1995 deletions

3
.env
View File

@ -18,7 +18,8 @@ SHOPRO_WEBSOCKET_PATH = /infra/ws
SHOPRO_DEV_PORT = 3000 SHOPRO_DEV_PORT = 3000
# 客户端静态资源地址 空=默认使用服务端指定的CDN资源地址前缀 | local=本地 | http(s)://xxx.xxx=自定义静态资源地址前缀 # 客户端静态资源地址 空=默认使用服务端指定的CDN资源地址前缀 | local=本地 | http(s)://xxx.xxx=自定义静态资源地址前缀
SHOPRO_STATIC_URL = https://file.sheepjs.com SHOPRO_STATIC_URL = http://test.yudao.iocoder.cn
### SHOPRO_STATIC_URL = https://file.sheepjs.com
# 是否开启直播 1 开启直播 | 0 关闭直播 (小程序官方后台未审核开通直播权限时请勿开启) # 是否开启直播 1 开启直播 | 0 关闭直播 (小程序官方后台未审核开通直播权限时请勿开启)
SHOPRO_MPLIVE_ON = 0 SHOPRO_MPLIVE_ON = 0

View File

@ -3,7 +3,7 @@
"appid": "__UNI__460BC4C", "appid": "__UNI__460BC4C",
"description": "基于 uni-app + Vue3 技术驱动的在线商城系统,内含诸多功能与丰富的活动,期待您的使用和反馈。", "description": "基于 uni-app + Vue3 技术驱动的在线商城系统,内含诸多功能与丰富的活动,期待您的使用和反馈。",
"versionName": "2.1.0", "versionName": "2.1.0",
"versionCode": 183, "versionCode": "183",
"transformPx": false, "transformPx": false,
"app-plus": { "app-plus": {
"usingComponents": true, "usingComponents": true,
@ -188,7 +188,8 @@
"setting": { "setting": {
"urlCheck": false, "urlCheck": false,
"minified": true, "minified": true,
"postcss": true "postcss": false,
"es6": false
}, },
"optimization": { "optimization": {
"subPackages": true "subPackages": true
@ -216,7 +217,7 @@
"h5": { "h5": {
"template": "index.html", "template": "index.html",
"router": { "router": {
"mode": "hash", "mode": "history",
"base": "./" "base": "./"
}, },
"sdkConfigs": { "sdkConfigs": {

View File

@ -307,6 +307,18 @@
"title": "编辑地址" "title": "编辑地址"
} }
}, },
{
"path": "goods_details_store/index",
"style": {
"navigationBarTitleText": "自提门店"
},
"meta": {
"auth": true,
"sync": true,
"title": "地址管理",
"group": "用户中心"
}
},
{ {
"path": "wallet/money", "path": "wallet/money",
"style": { "style": {

View File

@ -181,11 +181,11 @@
</view> </view>
</view> </view>
<!-- TODO 芋艿这里暂时没接入 --> <view v-if="!isEmpty(state.goodsInfo)">
<view v-if="state.data.goods"> <!-- 规格与数量弹框 -->
<s-select-groupon-sku <s-select-groupon-sku
:show="state.showSelectSku" :show="state.showSelectSku"
:goodsInfo="state.data.goods" :goodsInfo="state.goodsInfo"
:grouponAction="state.grouponAction" :grouponAction="state.grouponAction"
:grouponNum="state.grouponNum" :grouponNum="state.grouponNum"
@buy="onBuy" @buy="onBuy"
@ -193,6 +193,7 @@
@close="state.showSelectSku = false" @close="state.showSelectSku = false"
/> />
</view> </view>
</view> </view>
<s-empty v-if="!state.data && !state.loading" icon="/static/goods-empty.png" /> <s-empty v-if="!state.data && !state.loading" icon="/static/goods-empty.png" />
@ -203,25 +204,28 @@
import { computed, reactive } from 'vue'; import { computed, reactive } from 'vue';
import sheep from '@/sheep'; import sheep from '@/sheep';
import { onLoad } from '@dcloudio/uni-app'; import { onLoad } from '@dcloudio/uni-app';
import { useDurationTime } from '@/sheep/hooks/useGoods'; import { fen2yuan, useDurationTime } from '@/sheep/hooks/useGoods';
import { showShareModal } from '@/sheep/hooks/useModal'; import { showShareModal } from '@/sheep/hooks/useModal';
import { isEmpty } from 'lodash-es'; import { isEmpty } from 'lodash-es';
import CombinationApi from '@/sheep/api/promotion/combination'; 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, goodsId: 0, // ID
grouponAction: 'create', goodsInfo: {}, //
showSelectSku: false, showSelectSku: false, //
grouponNum: 0, selectedSkuPrice: {}, //
number: 0, activity: {}, //
activity: {}, grouponId: 0, // ID
grouponNum: 0, //
grouponAction: 'create', //
combinationHeadId: null, // combinationHeadId: null, //
loading: true,
}); });
// 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(
@ -231,15 +235,14 @@
desc: state.data.goods?.subtitle, desc: state.data.goods?.subtitle,
params: { params: {
page: '5', page: '5',
query: state.data.id, query: state.data.headRecord.id,
}, },
}, },
{ {
type: 'groupon', // type: 'groupon', //
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), //
price: state.data.goods?.price, // price: fen2yuan(state.data.headRecord.combinationPrice), //
original_price: state.data.goods?.original_price, //
}, },
); );
}); });
@ -251,33 +254,33 @@
}); });
} }
// TODO //
function onCreateGroupon() { function onCreateGroupon() {
state.grouponAction = 'create'; state.grouponAction = 'create';
state.grouponId = 0; state.grouponId = 0;
state.showSelectSku = true; state.showSelectSku = true;
} }
// TODO //
function onSkuChange(e) { function onSkuChange(e) {
state.selectedSkuPrice = e; state.selectedSkuPrice = e;
} }
// TODO //
function onJoinGroupon() { function onJoinGroupon() {
state.grouponAction = 'join'; state.grouponAction = 'join';
state.grouponId = state.data.activityId; state.grouponId = state.data.headRecord.activityId;
state.combinationHeadId = state.data.id; state.combinationHeadId = state.data.headRecord.id;
state.grouponNum = state.data.num; state.grouponNum = state.data.headRecord.userSize;
state.showSelectSku = true; state.showSelectSku = true;
} }
// 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.activity.id,
combinationHeadId: state.combinationHeadId, combinationHeadId: state.combinationHeadId,
items: [ items: [
{ {
@ -306,6 +309,25 @@
data.headRecord.activityId, data.headRecord.activityId,
); );
state.activity = activity; state.activity = activity;
state.grouponNum = activity.userSize;
//
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.goodsInfo = spu;
// 使
spu.skus.forEach((sku) => {
const product = activity.products.find((product) => product.skuId === sku.id);
if (product) {
sku.price = product.combinationPrice;
} else {
//
sku.stock = 0;
}
});
} else { } else {
state.data = null; state.data = null;
} }

View File

@ -62,7 +62,7 @@
</view> </view>
</view> </view>
<!-- 签到说明 TODO @科举这里改成已累计签到 --> <!-- 签到说明 TODO @芋艿签到这里改成已累计签到改版接入 sheepjs -->
<view class="bg-white ss-m-t-16 ss-p-t-30 ss-p-b-60 ss-p-x-40"> <view class="bg-white ss-m-t-16 ss-p-t-30 ss-p-b-60 ss-p-x-40">
<view class="activity-title ss-m-b-30">签到说明</view> <view class="activity-title ss-m-b-30">签到说明</view>
<view class="activity-des">1已累计签到{{state.signInfo.totalDay}}</view> <view class="activity-des">1已累计签到{{state.signInfo.totalDay}}</view>

View File

@ -7,7 +7,7 @@
@scrolltoupper="onScrollToUpper" @query="queryList"> @scrolltoupper="onScrollToUpper" @query="queryList">
<template #top> <template #top>
<!-- 撑一下顶部导航 --> <!-- 撑一下顶部导航 -->
<view style="height: 45px"></view> <view :style="{ height: sys_navBar + 'px' }"></view>
</template> </template>
<!-- style="transform: scaleY(-1)"必须写否则会导致列表倒置 --> <!-- style="transform: scaleY(-1)"必须写否则会导致列表倒置 -->
<!-- 注意不要直接在chat-item组件标签上设置style因为在微信小程序中是无效的请包一层view --> <!-- 注意不要直接在chat-item组件标签上设置style因为在微信小程序中是无效的请包一层view -->
@ -33,7 +33,9 @@
import { reactive, ref } from 'vue'; import { reactive, ref } from 'vue';
import KeFuApi from '@/sheep/api/promotion/kefu'; import KeFuApi from '@/sheep/api/promotion/kefu';
import { isEmpty } from '@/sheep/helper/utils'; import { isEmpty } from '@/sheep/helper/utils';
import sheep from '@/sheep';
const sys_navBar = sheep.$platform.navbar;
const messageList = ref([]); // const messageList = ref([]); //
const showNewMessageTip = ref(false); // const showNewMessageTip = ref(false); //
const backToTopStyle = reactive({ const backToTopStyle = reactive({
@ -67,7 +69,7 @@
}; };
/** 刷新消息列表 */ /** 刷新消息列表 */
const refreshMessageList = (message = undefined) => { const refreshMessageList = (message = undefined) => {
if (queryParams.pageNo != 1 && message !== undefined) { if (message !== undefined) {
showNewMessageTip.value = true; showNewMessageTip.value = true;
// //
pagingRef.value.addChatRecordData([message], false); pagingRef.value.addChatRecordData([message], false);
@ -87,8 +89,6 @@
return; return;
} }
showNewMessageTip.value = false; showNewMessageTip.value = false;
//
refreshMessageList();
}; };
defineExpose({ getMessageList, refreshMessageList }); defineExpose({ getMessageList, refreshMessageList });
</script> </script>

View File

@ -4,12 +4,20 @@
<view class="message-item ss-flex-col scroll-item"> <view class="message-item ss-flex-col scroll-item">
<view class="ss-flex ss-row-center ss-col-center"> <view class="ss-flex ss-row-center ss-col-center">
<!-- 日期 --> <!-- 日期 -->
<view v-if="message.contentType !== KeFuMessageContentTypeEnum.SYSTEM && showTime(message, messageIndex)" <view
class="date-message"> v-if="
message.contentType !== KeFuMessageContentTypeEnum.SYSTEM &&
showTime(message, messageIndex)
"
class="date-message"
>
{{ formatDate(message.createTime) }} {{ formatDate(message.createTime) }}
</view> </view>
<!-- 系统消息 --> <!-- 系统消息 -->
<view v-if="message.contentType === KeFuMessageContentTypeEnum.SYSTEM" class="system-message"> <view
v-if="message.contentType === KeFuMessageContentTypeEnum.SYSTEM"
class="system-message"
>
{{ message.content }} {{ message.content }}
</view> </view>
</view> </view>
@ -37,13 +45,16 @@
></image> ></image>
<!-- 内容 --> <!-- 内容 -->
<template v-if="message.contentType === KeFuMessageContentTypeEnum.TEXT"> <template v-if="message.contentType === KeFuMessageContentTypeEnum.TEXT">
<view class="message-box" :class="{'admin': message.senderType === UserTypeEnum.ADMIN}"> <view class="message-box" :class="{ admin: message.senderType === UserTypeEnum.ADMIN }">
<mp-html :content="replaceEmoji(message.content)" /> <mp-html :content="replaceEmoji(message.content)" />
</view> </view>
</template> </template>
<template v-if="message.contentType === KeFuMessageContentTypeEnum.IMAGE"> <template v-if="message.contentType === KeFuMessageContentTypeEnum.IMAGE">
<view class="message-box" :class="{'admin': message.senderType === UserTypeEnum.ADMIN}" <view
:style="{ width: '200rpx' }"> class="message-box"
:class="{ admin: message.senderType === UserTypeEnum.ADMIN }"
:style="{ width: '200rpx' }"
>
<su-image <su-image
class="message-img" class="message-img"
isPreview isPreview
@ -59,29 +70,23 @@
<template v-if="message.contentType === KeFuMessageContentTypeEnum.PRODUCT"> <template v-if="message.contentType === KeFuMessageContentTypeEnum.PRODUCT">
<GoodsItem <GoodsItem
:goodsData="getMessageContent(message)" :goodsData="getMessageContent(message)"
@tap=" @tap="sheep.$router.go('/pages/goods/index', { id: getMessageContent(message).spuId })"
sheep.$router.go('/pages/goods/index', {
id: getMessageContent(message).id,
})
"
/> />
</template> </template>
<template v-if="message.contentType === KeFuMessageContentTypeEnum.ORDER"> <template v-if="message.contentType === KeFuMessageContentTypeEnum.ORDER">
<OrderItem <OrderItem
:orderData="getMessageContent(message)" :orderData="getMessageContent(message)"
@tap=" @tap="sheep.$router.go('/pages/order/detail', { id: getMessageContent(message).id })"
sheep.$router.go('/pages/order/detail', {
id: getMessageContent(message).id,
})
"
/> />
</template> </template>
<!-- user头像 --> <!-- user头像 -->
<image <image
v-if="message.senderType === UserTypeEnum.MEMBER" v-if="message.senderType === UserTypeEnum.MEMBER"
class="chat-avatar ss-m-l-24" class="chat-avatar ss-m-l-24"
:src="sheep.$url.cdn(message.senderAvatar) || :src="
sheep.$url.static('/static/img/shop/chat/default.png')" sheep.$url.cdn(message.senderAvatar) ||
sheep.$url.static('/static/img/shop/chat/default.png')
"
mode="aspectFill" mode="aspectFill"
> >
</image> </image>
@ -115,7 +120,7 @@
messageList: { messageList: {
type: Array, type: Array,
default: () => [], default: () => [],
} },
}); });
const getMessageContent = computed(() => (item) => JSON.parse(item.content)); // const getMessageContent = computed(() => (item) => JSON.parse(item.content)); //

View File

@ -9,9 +9,17 @@
</view> </view>
</view> </view>
<view class="menu-list ss-flex ss-flex-wrap"> <view class="menu-list ss-flex ss-flex-wrap">
<view v-for="(item, index) in state.menuList" :key="index" class="item-box ss-flex-col ss-col-center" <view
@tap="sheep.$router.go(item.path)"> v-for="(item, index) in state.menuList"
<image class="menu-icon ss-m-b-10" :src="sheep.$url.static(item.img)" mode="aspectFill"></image> :key="index"
class="item-box ss-flex-col ss-col-center"
@tap="sheep.$router.go(item.path)"
>
<image
class="menu-icon ss-m-b-10"
:src="sheep.$url.static(item.img)"
mode="aspectFill"
></image>
<view>{{ item.title }}</view> <view>{{ item.title }}</view>
</view> </view>
</view> </view>
@ -23,7 +31,8 @@
import { reactive } from 'vue'; import { reactive } from 'vue';
const state = reactive({ const state = reactive({
menuList: [{ menuList: [
{
img: '/static/img/shop/commission/commission_icon1.png', img: '/static/img/shop/commission/commission_icon1.png',
title: '我的团队', title: '我的团队',
path: '/pages/commission/team', path: '/pages/commission/team',
@ -49,23 +58,21 @@
// path: '/pages/commission/apply', // path: '/pages/commission/apply',
// isAgentFrom: true, // isAgentFrom: true,
// }, // },
// todo @
{ {
img: '/static/img/shop/commission/commission_icon7.png', img: '/static/img/shop/commission/commission_icon7.png',
title: '邀请海报', title: '邀请海报',
path: 'action:showShareModal', path: 'action:showShareModal',
}, },
// TODO @ icon
{ {
// img: '/static/img/shop/commission/commission_icon7.png', img: '/static/img/shop/commission/commission_icon8.png',
title: '推广排行', title: '推广排行',
path: '/pages/commission/promoter', path: '/pages/commission/promoter',
}, },
{ {
// img: '/static/img/shop/commission/commission_icon7.png', img: '/static/img/shop/commission/commission_icon9.png',
title: '佣金排行', title: '佣金排行',
path: '/pages/commission/commission-ranking', path: '/pages/commission/commission-ranking',
} },
], ],
}); });
</script> </script>

View File

@ -76,7 +76,7 @@
shareInfo: {}, shareInfo: {},
}); });
// TODO // TODO @puhui999
function onShareGoods(goodsInfo) { function onShareGoods(goodsInfo) {
state.shareInfo = $share.getShareInfo( state.shareInfo = $share.getShareInfo(
{ {

View File

@ -1,8 +1,29 @@
<!-- 页面 TODO 芋艿该页面的实现代码需要优化包括 js css以及相关的样式设计 --> <!-- 页面 TODO 芋艿该页面的实现代码需要优化包括 js css以及相关的样式设计 -->
<template> <template>
<s-layout title="我的团队" :class="state.scrollTop ? 'team-wrap' : ''" navbar="inner"> <s-layout title="我的团队" :class="state.scrollTop ? 'team-wrap' : ''" navbar="inner">
<view class="promoter-list">
<view <view
class="header-box"
:style="[
{
marginTop: '-' + Number(statusBarHeight + 88) + 'rpx',
paddingTop: Number(statusBarHeight + 108) + 'rpx',
},
]"
>
<!-- 推广数据总览 -->
<view class="team-data-box ss-flex ss-col-center ss-row-between" style="width: 100%">
<view class="data-card" style="width: 100%">
<view class="total-item" style="width: 100%">
<view class="item-title" style="text-align: center">推广人数</view>
<view class="total-num" style="text-align: center">
{{ state.summary.firstBrokerageUserCount + state.summary.secondBrokerageUserCount || 0 }}
</view>
</view>
</view>
</view>
</view>
<view class="promoter-list">
<!--<view
class="promoterHeader bg-color" class="promoterHeader bg-color"
style="backgroundcolor: #e93323 !important; height: 218rpx; color: #fff" style="backgroundcolor: #e93323 !important; height: 218rpx; color: #fff"
> >
@ -21,9 +42,9 @@
</view> </view>
<view class="iconfont icon-tuandui" /> <view class="iconfont icon-tuandui" />
</view> </view>
</view> </view>-->
<view style="padding: 0 30rpx"> <view style="padding: 0 20rpx">
<view class="nav acea-row row-around l1"> <view class="nav acea-row row-around l1" style="margin-top:20rpx;">
<view :class="state.level == 1 ? 'item on' : 'item'" @click="setType(1)"> <view :class="state.level == 1 ? 'item on' : 'item'" @click="setType(1)">
一级({{ state.summary.firstBrokerageUserCount || 0 }}) 一级({{ state.summary.firstBrokerageUserCount || 0 }})
</view> </view>
@ -152,7 +173,7 @@
</view> </view>
</block> </block>
<block v-if="state.pagination.list.length === 0"> <block v-if="state.pagination.list.length === 0">
<view style="text-align: center">暂无推广人数</view> <view style="text-align: center;margin-top:30rpx;">暂无推广人数</view>
</block> </block>
</view> </view>
</view> </view>
@ -456,7 +477,7 @@
.promoter-list .nav .item.on { .promoter-list .nav .item.on {
border-bottom: 5rpx solid; border-bottom: 5rpx solid;
// $theme-color // $theme-color
color: red; color: var(--ui-BG-Main);
// $theme-color // $theme-color
} }

View File

@ -15,7 +15,10 @@
<view class="num-title">可提现金额</view> <view class="num-title">可提现金额</view>
<view class="wallet-num">{{ fen2yuan(state.brokerageInfo.brokeragePrice) }}</view> <view class="wallet-num">{{ fen2yuan(state.brokerageInfo.brokeragePrice) }}</view>
</view> </view>
<button class="ss-reset-button log-btn" @tap="sheep.$router.go('/pages/commission/wallet', { type: 2 })"> <button
class="ss-reset-button log-btn"
@tap="sheep.$router.go('/pages/commission/wallet', { type: 2 })"
>
提现记录 提现记录
</button> </button>
</view> </view>
@ -98,12 +101,23 @@
v-show="state.accountInfo.type === '2'" v-show="state.accountInfo.type === '2'"
> >
<view class="unit" /> <view class="unit" />
<!--银行改为下拉选择-->
<picker
@change="bankChange"
:value="state.bankListSelectedIndex"
:range="state.bankList"
range-key="label"
style="width: 100%"
>
<uni-easyinput <uni-easyinput
:inputBorder="false" :inputBorder="false"
class="ss-flex-1 ss-p-l-10" :value="state.accountInfo.bankName"
v-model="state.accountInfo.bankName" placeholder="请选择银行"
placeholder="请输入提现银行" suffixIcon="right"
disabled
:styles="{ disableColor: '#fff', borderColor: '#fff', color: '#333!important' }"
/> />
</picker>
</view> </view>
<!-- 开户地址 --> <!-- 开户地址 -->
<view class="card-title" v-show="state.accountInfo.type === '2'"></view> <view class="card-title" v-show="state.accountInfo.type === '2'"></view>
@ -152,6 +166,7 @@
import { fen2yuan } from '@/sheep/hooks/useGoods'; import { fen2yuan } from '@/sheep/hooks/useGoods';
import TradeConfigApi from '@/sheep/api/trade/config'; import TradeConfigApi from '@/sheep/api/trade/config';
import BrokerageApi from '@/sheep/api/trade/brokerage'; import BrokerageApi from '@/sheep/api/trade/brokerage';
import DictApi from '@/sheep/api/system/dict';
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;
@ -176,6 +191,8 @@
frozenDays: 0, // frozenDays: 0, //
minPrice: 0, // minPrice: 0, //
withdrawTypes: [], // withdrawTypes: [], //
bankList: [], //
bankListSelectedIndex: '', // bankList index
}); });
// //
@ -186,7 +203,7 @@
// //
const onConfirm = async () => { const onConfirm = async () => {
// //
debugger; //debugger;
if ( if (
!state.accountInfo.price || !state.accountInfo.price ||
state.accountInfo.price > state.brokerageInfo.price || state.accountInfo.price > state.brokerageInfo.price ||
@ -215,12 +232,12 @@
confirmText: '查看记录', confirmText: '查看记录',
success: (res) => { success: (res) => {
if (res.confirm) { if (res.confirm) {
sheep.$router.go('/pages/commission/wallet', { type: 2 }) sheep.$router.go('/pages/commission/wallet', { type: 2 });
return; return;
} }
getBrokerageUser(); getBrokerageUser();
state.accountInfo = {}; state.accountInfo = {};
} },
}); });
}; };
@ -245,10 +262,29 @@
} }
} }
//
async function getDictDataListByType() {
let { code, data } = await DictApi.getDictDataListByType('brokerage_bank_name');
if (code !== 0) {
return;
}
if (data && data.length > 0) {
state.bankList = data;
}
}
//
function bankChange(e) {
const value = e.detail.value;
state.bankListSelectedIndex = value;
state.accountInfo.bankName = state.bankList[value].label;
}
onBeforeMount(() => { onBeforeMount(() => {
getWithdrawRules(); getWithdrawRules();
getBrokerageUser() getBrokerageUser();
}) getDictDataListByType(); //
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -107,7 +107,6 @@
}, },
]; ];
// TODO yunai:
function onTabsChange(e) { function onTabsChange(e) {
state.currentTab = e.index; state.currentTab = e.index;
state.type = e.value; state.type = e.value;

View File

@ -27,21 +27,37 @@
</view> </view>
<!-- 评价 --> <!-- 评价 -->
<view class="area-box"> <view class="area-box">
<uni-easyinput :inputBorder="false" type="textarea" maxlength="120" autoHeight <uni-easyinput
:inputBorder="false"
type="textarea"
maxlength="120"
autoHeight
v-model="state.commentList[index].content" v-model="state.commentList[index].content"
placeholder="宝贝满足你的期待吗?说说你的使用心得,分享给想买的他们吧~" /> placeholder="宝贝满足你的期待吗?说说你的使用心得,分享给想买的他们吧~"
<!-- TODO 芋艿文件上传 --> />
<view class="img-box"> <view class="img-box">
<s-uploader v-model:url="state.commentList[index].images" fileMediatype="image" <s-uploader
limit="9" mode="grid" :imageStyles="{ width: '168rpx', height: '168rpx' }" /> v-model:url="state.commentList[index].images"
fileMediatype="image"
limit="9"
mode="grid"
:imageStyles="{ width: '168rpx', height: '168rpx' }"
@success="(payload) => uploadSuccess(payload, index)"
/>
</view>
</view>
<view class="checkbox-container">
<checkbox-group @change="(event) => toggleAnonymous(index, event)">
<label>
<checkbox value="anonymousChecked" />
匿名评论
</label>
</checkbox-group>
</view> </view>
</view> </view>
</view> </view>
</view> </view>
</view> </view>
</view>
<!-- TODO 芋艿是否匿名 -->
<su-fixed bottom placeholder> <su-fixed bottom placeholder>
<view class="foot_box ss-flex ss-row-center ss-col-center"> <view class="foot_box ss-flex ss-row-center ss-col-center">
<button class="ss-reset-button post-btn ui-BG-Main-Gradient ui-Shadow-Main" @tap="onSubmit"> <button class="ss-reset-button post-btn ui-BG-Main-Gradient ui-Shadow-Main" @tap="onSubmit">
@ -55,15 +71,30 @@
<script setup> <script setup>
import sheep from '@/sheep'; import sheep from '@/sheep';
import { onLoad } from '@dcloudio/uni-app'; import { onLoad } from '@dcloudio/uni-app';
import { reactive } from 'vue'; import { reactive, ref } from 'vue';
import OrderApi from '@/sheep/api/trade/order'; import OrderApi from '@/sheep/api/trade/order';
const state = reactive({ const state = reactive({
orderInfo: {}, orderInfo: {},
commentList: [], commentList: [],
id: null id: null,
}); });
/**
* 切换是否匿名
*
* @param commentIndex 当前评论下标
* @param event 复选框事件
*/
function toggleAnonymous(commentIndex, event) {
state.commentList[commentIndex].anonymous = event.detail.value[0] === 'anonymousChecked';
}
/**
* 发布评论
*
* @returns {Promise<void>}
*/
async function onSubmit() { async function onSubmit() {
// //
for (const comment of state.commentList) { for (const comment of state.commentList) {
@ -73,17 +104,27 @@
sheep.$router.back(); sheep.$router.back();
} }
/**
* 图片添加到表单
*
* @param payload 上传成功后的回调数据
* @param commentIndex 当前评论的下标
*/
function uploadSuccess(payload, commentIndex) {
state.commentList[commentIndex].picUrls = state.commentList[commentIndex].images;
}
onLoad(async (options) => { onLoad(async (options) => {
if (!options.id) { if (!options.id) {
sheep.$helper.toast(`缺少订单信息,请检查`); sheep.$helper.toast(`缺少订单信息,请检查`);
return return;
} }
state.id = options.id; state.id = options.id;
const { code, data } = await OrderApi.getOrder(state.id); const { code, data } = await OrderApi.getOrder(state.id);
if (code !== 0) { if (code !== 0) {
sheep.$helper.toast('无待评价订单'); sheep.$helper.toast('无待评价订单');
return return;
} }
// //
data.items.forEach((item) => { data.items.forEach((item) => {
@ -93,7 +134,7 @@
descriptionScores: 5, descriptionScores: 5,
benefitScores: 5, benefitScores: 5,
content: '', content: '',
picUrls: [] picUrls: [],
}); });
}); });
state.orderInfo = data; state.orderInfo = data;
@ -135,6 +176,10 @@
} }
} }
.checkbox-container {
padding: 10rpx;
}
.post-btn { .post-btn {
width: 690rpx; width: 690rpx;
line-height: 80rpx; line-height: 80rpx;

View File

@ -1,6 +1,6 @@
<!-- 商品评论的分页 --> <!-- 商品评论的分页 -->
<template> <template>
<s-layout title="全部评"> <s-layout title="全部评">
<su-tabs <su-tabs
:list="state.type" :list="state.type"
:scrollable="false" :scrollable="false"
@ -16,6 +16,7 @@
<s-empty v-if="state.pagination.total === 0" text="暂无数据" icon="/static/data-empty.png" /> <s-empty v-if="state.pagination.total === 0" text="暂无数据" icon="/static/data-empty.png" />
<!-- 下拉 --> <!-- 下拉 -->
<uni-load-more <uni-load-more
icon-type="auto"
v-if="state.pagination.total > 0" v-if="state.pagination.total > 0"
:status="state.loadStatus" :status="state.loadStatus"
:content-text="{ :content-text="{

View File

@ -2,7 +2,6 @@
<su-fixed bottom placeholder :val="44"> <su-fixed bottom placeholder :val="44">
<view> <view>
<view v-for="activity in props.activityList" :key="activity.id"> <view v-for="activity in props.activityList" :key="activity.id">
<!-- TODO 芋艿拼团 -->
<view <view
class="activity-box ss-p-x-38 ss-flex ss-row-between ss-col-center" class="activity-box ss-p-x-38 ss-flex ss-row-between ss-col-center"
:class="activity.type === 1 ? 'seckill-box' : 'groupon-box'" :class="activity.type === 1 ? 'seckill-box' : 'groupon-box'"
@ -14,7 +13,6 @@
:src="sheep.$url.static('/static/img/shop/goods/seckill-icon.png')" :src="sheep.$url.static('/static/img/shop/goods/seckill-icon.png')"
class="activity-icon" class="activity-icon"
/> />
<!-- TODO 芋艿拼团 -->
<image <image
v-else-if="activity.type === 3" v-else-if="activity.type === 3"
:src="sheep.$url.static('/static/img/shop/goods/groupon-icon.png')" :src="sheep.$url.static('/static/img/shop/goods/groupon-icon.png')"
@ -33,7 +31,6 @@
<script setup> <script setup>
import sheep from '@/sheep'; import sheep from '@/sheep';
// TODO
const seckillBg = sheep.$url.css('/static/img/shop/goods/seckill-tip-bg.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'); const grouponBg = sheep.$url.css('/static/img/shop/goods/groupon-tip-bg.png');

View File

@ -54,7 +54,7 @@
<view class="origin-price ss-flex ss-col-center" v-if="state.goodsInfo.price"> <view class="origin-price ss-flex ss-col-center" v-if="state.goodsInfo.price">
单买价 单买价
<view class="origin-price-text"> <view class="origin-price-text">
{{ fen2yuan(state.goodsInfo.price) }} {{ fen2yuan(state.goodsInfo.marketPrice) }}
</view> </view>
</view> </view>
</view> </view>
@ -80,7 +80,7 @@
<!-- 功能卡片 --> <!-- 功能卡片 -->
<view class="detail-cell-card detail-card ss-flex-col"> <view class="detail-cell-card detail-card ss-flex-col">
<!-- 规格 --> <!-- 规格 -->
<detail-cell-sku :sku="state.selectedSkuPrice" @tap="state.showSelectSku = true" /> <detail-cell-sku :sku="state.selectedSku" @tap="state.showSelectSku = true" />
</view> </view>
<!-- 参团列表 --> <!-- 参团列表 -->
@ -104,7 +104,6 @@
<detail-content-card class="detail-content-selector" :content="state.goodsInfo.description" /> <detail-content-card class="detail-content-selector" :content="state.goodsInfo.description" />
<!-- 商品tabbar --> <!-- 商品tabbar -->
<!-- TODO: 已售罄预热 判断 设计-->
<detail-tabbar v-model="state.goodsInfo"> <detail-tabbar v-model="state.goodsInfo">
<view class="buy-box ss-flex ss-col-center ss-p-r-20"> <view class="buy-box ss-flex ss-col-center ss-p-r-20">
<button <button
@ -125,7 +124,12 @@
:disabled="state.goodsInfo.stock === 0 || state.activity.status !== 0" :disabled="state.goodsInfo.stock === 0 || state.activity.status !== 0"
> >
<view class="btn-price">{{ <view class="btn-price">{{
fen2yuan(state.activity.price || state.goodsInfo.price) fen2yuan(
state.selectedSku.price * state.selectedSku.count ||
state.activity.price * state.selectedSku.count ||
state.goodsInfo.price * state.selectedSku.count ||
state.goodsInfo.price,
)
}}</view> }}</view>
<view v-if="state.activity.startTime > new Date().getTime()"></view> <view v-if="state.activity.startTime > new Date().getTime()"></view>
<view v-else-if="state.activity.endTime <= new Date().getTime()">已结束</view> <view v-else-if="state.activity.endTime <= new Date().getTime()">已结束</view>
@ -168,7 +172,7 @@
goodsInfo: {}, // goodsInfo: {}, //
goodsSwiper: [], // goodsSwiper: [], //
showSelectSku: false, // showSelectSku: false, //
selectedSkuPrice: {}, // selectedSku: {}, //
activity: {}, // activity: {}, //
grouponId: 0, // ID grouponId: 0, // ID
grouponNum: 0, // grouponNum: 0, //
@ -183,7 +187,7 @@
// //
function onSkuChange(e) { function onSkuChange(e) {
state.selectedSkuPrice = e; state.selectedSku = e;
} }
function onSkuClose() { function onSkuClose() {
@ -199,6 +203,7 @@
/** /**
* 去参团 * 去参团
*
* @param record 团长的团购记录 * @param record 团长的团购记录
*/ */
function onJoinGroupon(record) { function onJoinGroupon(record) {
@ -227,7 +232,6 @@
} }
// //
// TODO @
const shareInfo = computed(() => { const shareInfo = computed(() => {
if (isEmpty(state.activity)) return {}; if (isEmpty(state.activity)) return {};
return sheep.$platform.share.getShareInfo( return sheep.$platform.share.getShareInfo(
@ -262,9 +266,23 @@
// //
const { data: spu } = await SpuApi.getSpuDetail(activity.spuId); const { data: spu } = await SpuApi.getSpuDetail(activity.spuId);
state.goodsId = spu.id; state.goodsId = spu.id;
activity.products.forEach((product) => {
spu.price = Math.min(spu.price, product.combinationPrice); // SPU //
spu.price = activity.products.reduce((min, product) => {
return Math.min(min, product.combinationPrice || Infinity);
}, Infinity);
// 使
spu.skus.forEach((sku) => {
const product = activity.products.find((product) => product.skuId === sku.id);
if (product) {
sku.price = product.combinationPrice;
} else {
//
sku.stock = 0;
}
}); });
// //
state.skeletonLoading = false; state.skeletonLoading = false;
if (code === 0) { if (code === 0) {

View File

@ -7,47 +7,30 @@
<!-- 骨架屏 --> <!-- 骨架屏 -->
<detailSkeleton v-if="state.skeletonLoading" /> <detailSkeleton v-if="state.skeletonLoading" />
<!-- 下架/售罄提醒 --> <!-- 下架/售罄提醒 -->
<s-empty v-else-if="state.goodsInfo === null" text="商品不存在或已下架" icon="/static/soldout-empty.png" showAction <s-empty
actionText="再逛逛" actionUrl="/pages/goods/list" /> v-else-if="state.goodsInfo === null"
text="商品不存在或已下架"
icon="/static/soldout-empty.png"
showAction
actionText="再逛逛"
actionUrl="/pages/goods/list"
/>
<block v-else> <block v-else>
<view class="detail-swiper-selector"> <view class="detail-swiper-selector">
<!-- 商品轮播图 --> <!-- 商品轮播图 -->
<su-swiper class="ss-m-b-14" isPreview :list="formatGoodsSwiper(state.goodsInfo.sliderPicUrls)" <su-swiper
otStyle="tag" imageMode="widthFix" dotCur="bg-mask-40" :seizeHeight="750" /> class="ss-m-b-14"
<!-- 限时折扣 --> isPreview
<view class="discount" v-if="setShow"> :list="formatGoodsSwiper(state.goodsInfo.sliderPicUrls)"
<image class="disImg" src="../../static/images/dis.png"></image> otStyle="tag"
<view class="discountCont"> imageMode="widthFix"
<view class="disContT"> dotCur="bg-mask-40"
<view class="disContT1"> :seizeHeight="750"
<view class="disContT1P"> />
{{fen2yuan(settleData.price)}}
</view>
<view class="disContT1End">
直降{{fen2yuan( state.goodsInfo.price - settleData.price)}}
</view>
</view>
<view class="disContT2">
限时折扣
</view>
</view>
<view class="disContB">
<view class="disContB1">
价格{{fen2yuan(state.goodsInfo.price)}} 剩余{{settleData.stock}}
</view>
<view class="disContB2">
距结束仅剩
<countDown :tipText="' '" :bgColor="bgColor" :dayText="':'" :hourText="':'"
:minuteText="':'" :secondText="' '" :datatime="settleData.endTime / 1000"
:isDay="false" />
</view>
</view>
</view>
</view>
<!-- 限时折扣 -->
<!-- 价格+标题 --> <!-- 价格+标题 -->
<view class="title-card detail-card ss-p-y-40 ss-p-x-20"> <view class="title-card detail-card ss-p-y-40 ss-p-x-20">
<view class="ss-flex ss-row-between ss-col-center ss-m-b-26" v-if="!setShow"> <view class="ss-flex ss-row-between ss-col-center ss-m-b-26">
<view class="price-box ss-flex ss-col-bottom"> <view class="price-box ss-flex ss-col-bottom">
<view class="price-text ss-m-r-16"> <view class="price-text ss-m-r-16">
{{ fen2yuan(state.selectedSku.price || state.goodsInfo.price) }} {{ fen2yuan(state.selectedSku.price || state.goodsInfo.price) }}
@ -64,16 +47,23 @@
<!-- 满减送/限时折扣活动的提示 --> <!-- 满减送/限时折扣活动的提示 -->
<div class="tag-content"> <div class="tag-content">
<view class="tag-box ss-flex"> <view class="tag-box ss-flex">
<view class="tag ss-m-r-10" v-for="promos in state.activityInfo" :key="promos.id" <view
@tap="onActivity"> class="tag ss-m-r-10"
v-for="promos in state.activityInfo"
:key="promos.id"
@tap="onActivity"
>
{{ promos.name }} {{ promos.name }}
</view> </view>
</view> </view>
</div> </div>
<!-- 优惠劵@tap="state.showModel = true" --> <!-- 优惠劵 -->
<view class="get-coupon-box ss-flex ss-col-center ss-m-l-20" @tap="onActivity" <view
v-if="state.couponInfo.length"> class="get-coupon-box ss-flex ss-col-center ss-m-l-20"
@tap="state.showModel = true"
v-if="state.couponInfo.length"
>
<view class="discounts-title ss-m-r-8">领券</view> <view class="discounts-title ss-m-r-8">领券</view>
<text class="cicon-forward"></text> <text class="cicon-forward"></text>
</view> </view>
@ -84,30 +74,51 @@
<!-- 功能卡片 --> <!-- 功能卡片 -->
<view class="detail-cell-card detail-card ss-flex-col"> <view class="detail-cell-card detail-card ss-flex-col">
<detail-cell-sku v-model="state.selectedSku.goods_sku_text" :sku="state.selectedSku" <detail-cell-sku
@tap="state.showSelectSku = true" /> v-model="state.selectedSku.goods_sku_text"
:sku="state.selectedSku"
@tap="state.showSelectSku = true"
/>
</view> </view>
<!-- 规格与数量弹框 --> <!-- 规格与数量弹框 -->
<s-select-sku :goodsInfo="state.goodsInfo" :show="state.showSelectSku" @addCart="onAddCart" <s-select-sku
@buy="onBuy" @change="onSkuChange" @close="state.showSelectSku = false" /> :goodsInfo="state.goodsInfo"
:show="state.showSelectSku"
@addCart="onAddCart"
@buy="onBuy"
@change="onSkuChange"
@close="state.showSelectSku = false"
/>
</view> </view>
<!-- 评价 --> <!-- 评价 -->
<detail-comment-card class="detail-comment-selector" :goodsId="state.goodsId" /> <detail-comment-card class="detail-comment-selector" :goodsId="state.goodsId" />
<!-- 详情 --> <!-- 详情 -->
<detail-content-card class="detail-content-selector" :content="state.goodsInfo.description" /> <detail-content-card
class="detail-content-selector"
:content="state.goodsInfo.description"
/>
<!-- 活动跳转拼团/秒杀/砍价活动 --> <!-- 活动跳转拼团/秒杀/砍价活动 -->
<detail-activity-tip v-if="state.activityList.length > 0" :activity-list="state.activityList" /> <detail-activity-tip
v-if="state.activityList.length > 0"
:activity-list="state.activityList"
/>
<!-- 详情 tabbar --> <!-- 详情 tabbar -->
<detail-tabbar v-model="state.goodsInfo"> <detail-tabbar v-model="state.goodsInfo">
<view class="buy-box ss-flex ss-col-center ss-p-r-20" v-if="state.goodsInfo.stock > 0"> <view class="buy-box ss-flex ss-col-center ss-p-r-20" v-if="state.goodsInfo.stock > 0">
<button class="ss-reset-button add-btn ui-Shadow-Main" @tap="state.showSelectSku = true"> <button
class="ss-reset-button add-btn ui-Shadow-Main"
@tap="state.showSelectSku = true"
>
加入购物车 加入购物车
</button> </button>
<button class="ss-reset-button buy-btn ui-Shadow-Main" @tap="state.showSelectSku = true"> <button
class="ss-reset-button buy-btn ui-Shadow-Main"
@tap="state.showSelectSku = true"
>
立即购买 立即购买
</button> </button>
</view> </view>
@ -117,38 +128,32 @@
</detail-tabbar> </detail-tabbar>
<!-- 优惠劵弹窗 --> <!-- 优惠劵弹窗 -->
<!-- <s-coupon-get v-model="state.couponInfo" :show="state.showModel" @close="state.showModel = false" <s-coupon-get
@get="onGet" /> --> v-model="state.couponInfo"
:show="state.showModel"
@close="state.showModel = false"
@get="onGet"
/>
<!-- 满减送/限时折扣活动弹窗 --> <!-- 满减送/限时折扣活动弹窗 -->
<s-activity-pop v-model="state" :show="state.showActivityModel" <s-activity-pop
@close="state.showActivityModel = false" @get="onGet" /> v-model="state.activityInfo"
:show="state.showActivityModel"
@close="state.showActivityModel = false"
/>
</block> </block>
</s-layout> </s-layout>
</view> </view>
</template> </template>
<script setup> <script setup>
import { import { reactive, computed } from 'vue';
reactive, import { onLoad, onPageScroll } from '@dcloudio/uni-app';
computed,
ref
} from 'vue';
import {
onLoad,
onPageScroll
} from '@dcloudio/uni-app';
import sheep from '@/sheep'; import sheep from '@/sheep';
import CouponApi from '@/sheep/api/promotion/coupon'; import CouponApi from '@/sheep/api/promotion/coupon';
import ActivityApi from '@/sheep/api/promotion/activity'; import ActivityApi from '@/sheep/api/promotion/activity';
import FavoriteApi from '@/sheep/api/product/favorite'; import FavoriteApi from '@/sheep/api/product/favorite';
import { import { formatSales, formatGoodsSwiper, fen2yuan } from '@/sheep/hooks/useGoods';
formatSales,
formatGoodsSwiper,
fen2yuan,
handList,
handListPrice
} from '@/sheep/hooks/useGoods';
import detailNavbar from './components/detail/detail-navbar.vue'; import detailNavbar from './components/detail/detail-navbar.vue';
import detailCellSku from './components/detail/detail-cell-sku.vue'; import detailCellSku from './components/detail/detail-cell-sku.vue';
import detailTabbar from './components/detail/detail-tabbar.vue'; import detailTabbar from './components/detail/detail-tabbar.vue';
@ -156,22 +161,11 @@
import detailCommentCard from './components/detail/detail-comment-card.vue'; import detailCommentCard from './components/detail/detail-comment-card.vue';
import detailContentCard from './components/detail/detail-content-card.vue'; import detailContentCard from './components/detail/detail-content-card.vue';
import detailActivityTip from './components/detail/detail-activity-tip.vue'; import detailActivityTip from './components/detail/detail-activity-tip.vue';
import { import { isEmpty } from 'lodash-es';
isEmpty
} from 'lodash-es';
import SpuApi from '@/sheep/api/product/spu'; import SpuApi from '@/sheep/api/product/spu';
onPageScroll(() => { onPageScroll(() => {});
});
import countDown from '@/sheep/components/countDown/index.vue'
const bgColor = {
'bgColor': '#E93323',
'Color': '#fff',
'width': '44rpx',
'timeTxtwidth': '16rpx',
'isDay': true
}
const isLogin = computed(() => sheep.$store('user').isLogin); const isLogin = computed(() => sheep.$store('user').isLogin);
const state = reactive({ const state = reactive({
goodsId: 0, goodsId: 0,
@ -182,19 +176,13 @@
showModel: false, // Coupon showModel: false, // Coupon
couponInfo: [], // Coupon couponInfo: [], // Coupon
showActivityModel: false, // / Activity showActivityModel: false, // / Activity
activityInfo: [], // / Activity activityInfo: [], // / Activity TODO
activityList: [], // // Activity activityList: [], // // Activity
}); });
// //
function onSkuChange(e) { function onSkuChange(e) {
if (e.type == 4) {
settleData.value = e
setShow.value = true
} else {
state.selectedSku = e; state.selectedSku = e;
setShow.value = false
}
} }
// //
@ -208,17 +196,19 @@
// //
function onBuy(e) { function onBuy(e) {
if (!e.id) { if (!state.selectedSku.id) {
sheep.$helper.toast('请选择商品规格'); sheep.$helper.toast('请选择商品规格');
return; return;
} }
sheep.$router.go('/pages/order/confirm', { sheep.$router.go('/pages/order/confirm', {
data: JSON.stringify({ data: JSON.stringify({
items: [{ items: [
{
skuId: e.id, skuId: e.id,
count: e.goods_num, count: e.goods_num,
categoryId: state.goodsInfo.categoryId categoryId: state.goodsInfo.categoryId,
}] },
],
}), }),
}); });
} }
@ -230,9 +220,7 @@
// //
async function onGet(id) { async function onGet(id) {
const { const { code } = await CouponApi.takeCoupon(id);
code
} = await CouponApi.takeCoupon(id);
if (code !== 0) { if (code !== 0) {
return; return;
} }
@ -244,10 +232,10 @@
}, 1000); }, 1000);
} }
// TODO
const shareInfo = computed(() => { const shareInfo = computed(() => {
if (isEmpty(state.goodsInfo)) return {}; if (isEmpty(state.goodsInfo)) return {};
return sheep.$platform.share.getShareInfo({ return sheep.$platform.share.getShareInfo(
{
title: state.goodsInfo.name, title: state.goodsInfo.name,
image: sheep.$url.cdn(state.goodsInfo.picUrl), image: sheep.$url.cdn(state.goodsInfo.picUrl),
desc: state.goodsInfo.introduction, desc: state.goodsInfo.introduction,
@ -255,58 +243,24 @@
page: '2', page: '2',
query: state.goodsInfo.id, query: state.goodsInfo.id,
}, },
}, { },
{
type: 'goods', // type: 'goods', //
title: state.goodsInfo.name, // title: state.goodsInfo.name, //
image: sheep.$url.cdn(state.goodsInfo.picUrl), // image: sheep.$url.cdn(state.goodsInfo.picUrl), //
price: fen2yuan(state.goodsInfo.price), // price: fen2yuan(state.goodsInfo.price), //
original_price: fen2yuan(state.goodsInfo.marketPrice), // original_price: fen2yuan(state.goodsInfo.marketPrice), //
}); },
);
}); });
async function getCoupon() { async function getCoupon() {
const { const { code, data } = await CouponApi.getCouponTemplateList(state.goodsId, 2, 10);
code,
data
} = await CouponApi.getCouponTemplateList(state.goodsId, 2, 10);
if (code === 0) { if (code === 0) {
state.couponInfo = data; state.couponInfo = data;
} }
} }
//
const setShow = ref(false)
const settleData = ref()
async function getSettlementByIds(ids) {
const { data } = await SpuApi.getSettlementProduct(ids);
settleData.value = handle(data)
state.goodsInfo.skus = handListPrice(state.goodsInfo.skus, data[0].skus)
}
//
function handle(array) {
let setList = {}
array.some(item => {
return item.skus.some(items => {
if (items.type === 4) {
setShow.value = true;
setList = items;
return true; // truesome
}
return false; //
});
});
//
state.goodsInfo.skus.forEach(item => {
if (item.id == setList.skuId) {
setList.stock = item.stock
}
})
return setList
}
onLoad((options) => { onLoad((options) => {
// //
if (!options.id) { if (!options.id) {
@ -324,6 +278,7 @@
// //
state.skeletonLoading = false; state.skeletonLoading = false;
state.goodsInfo = res.data; state.goodsInfo = res.data;
// //
if (isLogin.value) { if (isLogin.value) {
FavoriteApi.isFavoriteExists(state.goodsId, 'goods').then((res) => { FavoriteApi.isFavoriteExists(state.goodsId, 'goods').then((res) => {
@ -338,24 +293,13 @@
// 2. // 2.
getCoupon(); getCoupon();
// 3. // 3.
ActivityApi.getActivityListBySpuId(state.goodsId).then((res) => { ActivityApi.getActivityListBySpuId(state.goodsId).then((res) => {
if (res.code !== 0) { if (res.code !== 0) {
return; return;
} }
let activData = handList(res.data) state.activityList = res.data;
activData.forEach(activity => {
if ([1, 2, 3].includes(activity.type)) { // //
state.activityList.push(activity);
} else if (activity.type === 5) { //
state.activityInfo.push(activity);
} else { // TODO
// console.log('');
}
})
}); });
//
getSettlementByIds(state.goodsId)
}); });
</script> </script>
@ -504,101 +448,4 @@
color: #333333; color: #333333;
} }
} }
//
.discount {
width: 750rpx;
height: 100rpx;
// background-color: red;
overflow: hidden;
position: relative;
}
.disImg {
width: 750rpx;
height: 100rpx;
position: absolute;
top: 0;
z-index: -1;
}
.discountCont {
width: 680rpx;
height: 90rpx;
margin: 10rpx auto 0 auto;
// background-color: gold;
}
.disContT {
width: 680rpx;
height: 50rpx;
display: flex;
justify-content: space-between;
}
.disContT1 {
width: 400rpx;
height: 50rpx;
// background-color: green;
display: flex;
justify-content: flex-start;
align-items: center;
}
.disContT2 {
width: 200rpx;
height: 50rpx;
line-height: 50rpx;
// background-color: gold;
font-size: 30rpx;
text-align: end;
color: white;
font-weight: bolder;
font-style: oblique 20deg;
letter-spacing: .1rem;
}
.disContT1P {
color: white;
font-weight: bold;
font-size: 28rpx;
}
.disContT1End {
// width: 180rpx;
padding: 0 10rpx;
height: 30rpx;
line-height: 28rpx;
text-align: center;
font-weight: bold;
background-color: white;
color: #ff3000;
font-size: 23rpx;
border-radius: 20rpx;
margin-left: 10rpx;
}
.disContB {
width: 680rpx;
height: 40rpx;
display: flex;
justify-content: space-between;
font-size: 20rpx;
color: white;
align-items: center;
}
.disContB1 {
width: 300rpx;
height: 40rpx;
line-height: 40rpx;
}
.disContB2 {
width: 300rpx;
height: 40rpx;
line-height: 40rpx;
display: flex;
justify-content: flex-end;
}
</style> </style>

View File

@ -107,6 +107,7 @@
skuId: item.sku.id, skuId: item.sku.id,
count: item.count, count: item.count,
cartId: item.id, cartId: item.id,
categoryId: item.spu.categoryId
}) })
goods_list.push({ goods_list.push({
// goods_id: item.goods_id, // goods_id: item.goods_id,
@ -124,12 +125,7 @@
} }
sheep.$router.go('/pages/order/confirm', { sheep.$router.go('/pages/order/confirm', {
data: JSON.stringify({ data: JSON.stringify({
// order_type: 'goods', items
// goods_list,
items,
// from: 'cart',
deliveryType: 1,
pointStatus: false,
}), }),
}); });
} }

View File

@ -131,12 +131,13 @@
getGoodsList(); getGoodsList();
} }
onLoad(async () => { onLoad(async (params) => {
await getList(); await getList();
// first
if (state.style === 'first_one' || state.style === 'first_two') { //
onMenu(0); const foundCategory = state.categoryList.find(category => category.id === params.id);
} // onMenu onMenu(0)
onMenu(foundCategory ? state.categoryList.indexOf(foundCategory) : 0);
}); });
onReachBottom(() => { onReachBottom(() => {

View File

@ -2,51 +2,68 @@
<template> <template>
<view class="allAddress" :style="state.isPickUp ? '' : 'padding-top:10rpx;'"> <view class="allAddress" :style="state.isPickUp ? '' : 'padding-top:10rpx;'">
<view class="nav flex flex-wrap"> <view class="nav flex flex-wrap">
<view class="item font-color" :class="state.deliveryType === 1 ? 'on' : 'on2'" <view
@tap="switchDeliveryType(1)" v-if='state.isPickUp' /> class="item font-color"
<view class="item font-color" :class="state.deliveryType === 2 ? 'on' : 'on2'" :class="state.deliveryType === 1 ? 'on' : 'on2'"
@tap="switchDeliveryType(2)" v-if='state.isPickUp' /> @tap="switchDeliveryType(1)"
v-if="state.isPickUp"
/>
<view
class="item font-color"
:class="state.deliveryType === 2 ? 'on' : 'on2'"
@tap="switchDeliveryType(2)"
v-if="state.isPickUp"
/>
</view> </view>
<!-- 情况一收货地址的选择 --> <!-- 情况一收货地址的选择 -->
<view class='address flex flex-wrap flex-center ss-row-between' @tap='onSelectAddress' v-if='state.deliveryType === 1' <view
:style="state.isPickUp ? '':'border-top-left-radius: 14rpx;border-top-right-radius: 14rpx;'"> class="address flex flex-wrap flex-center ss-row-between"
<view class='addressCon' v-if="state.addressInfo.name"> @tap="onSelectAddress"
<view class='name'>{{ state.addressInfo.name }} v-if="state.deliveryType === 1"
<text class='phone'>{{ state.addressInfo.mobile }}</text> :style="state.isPickUp ? '' : 'border-top-left-radius: 14rpx;border-top-right-radius: 14rpx;'"
>
<view class="addressCon" v-if="state.addressInfo.name">
<view class="name"
>{{ state.addressInfo.name }}
<text class="phone">{{ state.addressInfo.mobile }}</text>
</view> </view>
<view class="flex flex-wrap"> <view class="flex flex-wrap">
<text class='default font-color' v-if="state.addressInfo.defaultStatus">[]</text> <text class="default font-color" v-if="state.addressInfo.defaultStatus">[]</text>
<text class="line2">{{ state.addressInfo.areaName }} {{ state.addressInfo.detailAddress }}</text> <text class="line2"
>{{ state.addressInfo.areaName }} {{ state.addressInfo.detailAddress }}</text
>
</view> </view>
</view> </view>
<view class='addressCon' v-else> <view class="addressCon" v-else>
<view class='setaddress'>设置收货地址</view> <view class="setaddress">设置收货地址</view>
</view> </view>
<view class='iconfont'> <view class="iconfont">
<view class="ss-rest-button"> <view class="ss-rest-button">
<text class="_icon-forward" /> <text class="_icon-forward" />
</view> </view>
</view> </view>
</view> </view>
<!-- 情况二门店的选择 --> <!-- 情况二门店的选择 -->
<view class='address flex flex-wrap flex-center ss-row-between' v-else @tap="onSelectAddress"> <view class="address flex flex-wrap flex-center ss-row-between" v-else @tap="onSelectAddress">
<view class='addressCon' v-if="state.pickUpInfo.name"> <view class="addressCon" v-if="state.pickUpInfo.name">
<view class='name'>{{ state.pickUpInfo.name }} <view class="name"
<text class='phone'>{{ state.pickUpInfo.phone }}</text> >{{ state.pickUpInfo.name }}
<text class="phone">{{ state.pickUpInfo.phone }}</text>
</view> </view>
<view class="line1"> {{ state.pickUpInfo.areaName }}{{ ', ' + state.pickUpInfo.detailAddress }} <view class="line1">
{{ state.pickUpInfo.areaName }}{{ ', ' + state.pickUpInfo.detailAddress }}
</view> </view>
</view> </view>
<view class='addressCon' v-else> <view class="addressCon" v-else>
<view class='setaddress'>选择自提门店</view> <view class="setaddress">选择自提门店</view>
</view> </view>
<view class='iconfont'> <view class="iconfont">
<view class="ss-rest-button"> <view class="ss-rest-button">
<text class="_icon-forward" /> <text class="_icon-forward" />
</view> </view>
</view> </view>
</view> </view>
<view class='line'> <view class="line">
<image :src="sheep.$url.static('/static/images/line.png', 'local')" /> <image :src="sheep.$url.static('/static/images/line.png', 'local')" />
</view> </view>
</view> </view>
@ -61,9 +78,9 @@
modelValue: { modelValue: {
type: Object, type: Object,
default() {}, default() {},
} },
}); });
const emits = defineEmits(['update:modelValue','change']); const emits = defineEmits(['update:modelValue']);
// computed // computed
const state = computed({ const state = computed({
@ -75,21 +92,21 @@
[name]: val, [name]: val,
}); });
return true; return true;
} },
}) });
}, },
set(val) { set(val) {
emits('update:modelValue', val); emits('update:modelValue', val);
} },
}) });
// //
function onSelectAddress() { function onSelectAddress() {
let emitName = 'SELECT_ADDRESS' let emitName = 'SELECT_ADDRESS';
let addressPage = '/pages/user/address/list?type=select'; let addressPage = '/pages/user/address/list?type=select';
if (state.value.deliveryType === 2) { if (state.value.deliveryType === 2) {
emitName = 'SELECT_PICK_UP_INFO' emitName = 'SELECT_PICK_UP_INFO';
addressPage = '/pages/user/goods_details_store/index' addressPage = '/pages/user/goods_details_store/index';
} }
uni.$once(emitName, (e) => { uni.$once(emitName, (e) => {
changeConsignee(e.addressInfo); changeConsignee(e.addressInfo);
@ -106,20 +123,18 @@
if (state.value.deliveryType === 2) { if (state.value.deliveryType === 2) {
state.value.pickUpInfo = addressInfo; state.value.pickUpInfo = addressInfo;
} }
emits('change')
} }
} }
// //
const switchDeliveryType = (type) => { const switchDeliveryType = (type) => {
state.value.deliveryType = type; state.value.deliveryType = type;
emits('change') };
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.allAddress .font-color { .allAddress .font-color {
color: #E93323!important color: #e93323 !important;
} }
.line2 { .line2 {
width: 504rpx; width: 504rpx;
@ -204,7 +219,7 @@
.allAddress .nav .item.on::before { .allAddress .nav .item.on::before {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
content: "快递配送"; content: '快递配送';
font-size: 28rpx; font-size: 28rpx;
display: block; display: block;
height: 0; height: 0;
@ -219,7 +234,7 @@
} }
.allAddress .nav .item:nth-of-type(2).on::before { .allAddress .nav .item:nth-of-type(2).on::before {
content: "到店自提"; content: '到店自提';
border-width: 0 0 80rpx 20rpx; border-width: 0 0 80rpx 20rpx;
border-radius: 36rpx 14rpx 0 0; border-radius: 36rpx 14rpx 0 0;
} }
@ -231,7 +246,7 @@
.allAddress .nav .item.on2::before { .allAddress .nav .item.on2::before {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
content: "到店自提"; content: '到店自提';
font-size: 28rpx; font-size: 28rpx;
display: block; display: block;
height: 0; height: 0;
@ -245,7 +260,7 @@
} }
.allAddress .nav .item:nth-of-type(1).on2::before { .allAddress .nav .item:nth-of-type(1).on2::before {
content: "快递配送"; content: '快递配送';
border-width: 0 60rpx 60rpx 0; border-width: 0 60rpx 60rpx 0;
border-radius: 14rpx 36rpx 0 0; border-radius: 14rpx 36rpx 0 0;
} }

View File

@ -1,18 +1,30 @@
<template> <template>
<s-layout title="确认订单"> <s-layout title="确认订单">
<!-- 头部地址选择配送地址自提地址 --> <!-- 头部地址选择配送地址自提地址 -->
<AddressSelection v-model="addressState" @change="getOrderInfo()" /> <AddressSelection v-model="addressState" />
<!-- 商品信息 --> <!-- 商品信息 -->
<view class="order-card-box ss-m-b-14"> <view class="order-card-box ss-m-b-14">
<s-goods-item v-for="item in state.orderInfo.items" :key="item.skuId" :img="item.picUrl" <s-goods-item
:title="item.spuName" :skuText="item.properties.map((property) => property.valueName).join(' ')" v-for="item in state.orderInfo.items"
:price="item.price" :num="item.count" marginBottom="10" /> :key="item.skuId"
:img="item.picUrl"
:title="item.spuName"
:skuText="item.properties.map((property) => property.valueName).join(' ')"
:price="item.price"
:num="item.count"
marginBottom="10"
/>
<view class="order-item ss-flex ss-col-center ss-row-between ss-p-x-20 bg-white ss-r-10"> <view class="order-item ss-flex ss-col-center ss-row-between ss-p-x-20 bg-white ss-r-10">
<view class="item-title">订单备注</view> <view class="item-title">订单备注</view>
<view class="ss-flex ss-col-center"> <view class="ss-flex ss-col-center">
<uni-easyinput maxlength="20" placeholder="建议留言前先与商家沟通" v-model="state.orderPayload.remark" <uni-easyinput
:inputBorder="false" :clearable="false" /> maxlength="20"
placeholder="建议留言前先与商家沟通"
v-model="state.orderPayload.remark"
:inputBorder="false"
:clearable="false"
/>
</view> </view>
</view> </view>
</view> </view>
@ -28,71 +40,121 @@
</text> </text>
</view> </view>
</view> </view>
<view class="order-item ss-flex ss-col-center ss-row-between" v-if="state.orderInfo.type === 0"> <view
class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderInfo.type === 0"
>
<view class="item-title">积分抵扣</view> <view class="item-title">积分抵扣</view>
<view class="ss-flex ss-col-center"> <view class="ss-flex ss-col-center">
{{ state.pointStatus ? '剩余积分' : '当前积分' }} {{ state.pointStatus ? '剩余积分' : '当前积分' }}
<image :src="sheep.$url.static('/static/img/shop/goods/score1.svg')" class="score-img" /> <image
:src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
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.usePoint
: state.orderInfo.totalPoint || 0
}}
</text> </text>
<checkbox-group @change="changeIntegral"> <checkbox-group @change="changeIntegral">
<checkbox :checked='state.pointStatus' <checkbox
:disabled="!state.orderInfo.totalPoint || state.orderInfo.totalPoint <= 0" /> :checked="state.pointStatus"
:disabled="!state.orderInfo.totalPoint || state.orderInfo.totalPoint <= 0"
/>
</checkbox-group> </checkbox-group>
</view> </view>
</view> </view>
<!-- 快递配置时信息的展示 --> <!-- 快递配置时信息的展示 -->
<view class="order-item ss-flex ss-col-center ss-row-between" v-if='addressState.deliveryType === 1'> <view
class="order-item ss-flex ss-col-center ss-row-between"
v-if="addressState.deliveryType === 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">
<text class="item-value ss-m-r-24" v-if="state.orderInfo.price.deliveryPrice > 0"> <text class="item-value ss-m-r-24" v-if="state.orderInfo.price.deliveryPrice > 0">
+{{ fen2yuan(state.orderInfo.price.deliveryPrice) }} +{{ fen2yuan(state.orderInfo.price.deliveryPrice) }}
</text> </text>
<view class='item-value ss-m-r-24' v-else></view> <view class="item-value ss-m-r-24" v-else></view>
</view> </view>
</view> </view>
<!-- 门店自提时需要填写姓名和手机号 --> <!-- 门店自提时需要填写姓名和手机号 -->
<view class="order-item ss-flex ss-col-center ss-row-between" v-if='addressState.deliveryType === 2'> <view
class="order-item ss-flex ss-col-center ss-row-between"
v-if="addressState.deliveryType === 2"
>
<view class="item-title">联系人</view> <view class="item-title">联系人</view>
<view class="ss-flex ss-col-center"> <view class="ss-flex ss-col-center">
<uni-easyinput maxlength="20" placeholder="请填写您的联系姓名" v-model="addressState.receiverName" <uni-easyinput
:inputBorder="false" :clearable="false" /> maxlength="20"
placeholder="请填写您的联系姓名"
v-model="addressState.receiverName"
:inputBorder="false"
:clearable="false"
/>
</view> </view>
</view> </view>
<view class="order-item ss-flex ss-col-center ss-row-between" v-if='addressState.deliveryType === 2'> <view
class="order-item ss-flex ss-col-center ss-row-between"
v-if="addressState.deliveryType === 2"
>
<view class="item-title">联系电话</view> <view class="item-title">联系电话</view>
<view class="ss-flex ss-col-center"> <view class="ss-flex ss-col-center">
<uni-easyinput maxlength="20" placeholder="请填写您的联系电话" v-model="addressState.receiverMobile" <uni-easyinput
:inputBorder="false" :clearable="false" /> maxlength="20"
placeholder="请填写您的联系电话"
v-model="addressState.receiverMobile"
:inputBorder="false"
:clearable="false"
/>
</view> </view>
</view> </view>
<!-- 优惠劵只有 type = 0 普通订单非拼团秒杀砍价才可以使用优惠劵 --> <!-- 优惠劵只有 type = 0 普通订单非拼团秒杀砍价才可以使用优惠劵 -->
<view class="order-item ss-flex ss-col-center ss-row-between" v-if="state.orderInfo.type === 0"> <view
class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderInfo.type === 0"
>
<view class="item-title">优惠券</view> <view class="item-title">优惠券</view>
<view class="ss-flex ss-col-center" @tap="state.showCoupon = true"> <view class="ss-flex ss-col-center" @tap="state.showCoupon = true">
<text class="item-value text-red" v-if="state.orderPayload.couponId > 0"> <text class="item-value text-red" v-if="state.orderPayload.couponId > 0">
-{{ fen2yuan(state.orderInfo.price.couponPrice) }} -{{ fen2yuan(state.orderInfo.price.couponPrice) }}
</text> </text>
<text class="item-value" :class="couponNumber > 0 ? 'text-red' : 'text-disabled'" v-else> <text
class="item-value"
:class="
state.couponInfo.filter((coupon) => coupon.match).length > 0
? 'text-red'
: 'text-disabled'
"
v-else
>
{{ {{
couponNumber > 0 ? couponNumber + ' 张可用' : '暂无可用优惠券' state.couponInfo.filter((coupon) => coupon.match).length > 0
? state.couponInfo.filter((coupon) => coupon.match).length + ' 张可用'
: '暂无可用优惠券'
}} }}
</text> </text>
<text class="_icon-forward item-icon" /> <text class="_icon-forward item-icon" />
</view> </view>
</view> </view>
<view class="order-item ss-flex ss-col-center ss-row-between" <view
v-if="state.orderInfo.price.discountPrice > 0"> class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderInfo.price.discountPrice > 0"
>
<view class="item-title">活动优惠</view> <view class="item-title">活动优惠</view>
<view class="ss-flex ss-col-center" @tap="state.showDiscount = true"> <view class="ss-flex ss-col-center">
<!-- @tap="state.showDiscount = true" TODO puhui999折扣后续要把优惠信息打进去 -->
<text class="item-value text-red"> <text class="item-value text-red">
-{{ fen2yuan(state.orderInfo.price.discountPrice) }} -{{ fen2yuan(state.orderInfo.price.discountPrice) }}
</text> </text>
<text class="_icon-forward item-icon" /> <text class="_icon-forward item-icon" />
</view> </view>
</view> </view>
<view class="order-item ss-flex ss-col-center ss-row-between" v-if="state.orderInfo.price.vipPrice > 0"> <view
class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderInfo.price.vipPrice > 0"
>
<view class="item-title">会员优惠</view> <view class="item-title">会员优惠</view>
<view class="ss-flex ss-col-center"> <view class="ss-flex ss-col-center">
<text class="item-value text-red"> <text class="item-value text-red">
@ -111,11 +173,19 @@
</view> </view>
<!-- 选择优惠券弹框 --> <!-- 选择优惠券弹框 -->
<s-coupon-select v-model="state.couponInfo" :show="state.showCoupon" @confirm="onSelectCoupon" <s-coupon-select
@close="state.showCoupon = false" /> v-model="state.couponInfo"
:show="state.showCoupon"
@confirm="onSelectCoupon"
@close="state.showCoupon = false"
/>
<!-- 满额折扣弹框 TODO 芋艿后续要把优惠信息打进去 --> <!-- 满额折扣弹框 TODO @puhui999折扣后续要把优惠信息打进去 -->
<s-discount-list v-model="state.orderInfo" :show="state.showDiscount" @close="state.showDiscount = false" /> <s-discount-list
v-model="state.orderInfo"
:show="state.showDiscount"
@close="state.showDiscount = false"
/>
<!-- 底部 --> <!-- 底部 -->
<su-fixed bottom :opacity="false" bg="bg-white" placeholder :noFixed="false" :index="200"> <su-fixed bottom :opacity="false" bg="bg-white" placeholder :noFixed="false" :index="200">
@ -125,7 +195,10 @@
{{ fen2yuan(state.orderInfo.price.payPrice) }} {{ fen2yuan(state.orderInfo.price.payPrice) }}
</view> </view>
</view> </view>
<button class="ss-reset-button ui-BG-Main-Gradient ss-r-40 submit-btn ui-Shadow-Main" @tap="onConfirm"> <button
class="ss-reset-button ui-BG-Main-Gradient ss-r-40 submit-btn ui-Shadow-Main"
@tap="onConfirm"
>
提交订单 提交订单
</button> </button>
</view> </view>
@ -134,20 +207,13 @@
</template> </template>
<script setup> <script setup>
import { import { reactive, ref, watch } from 'vue';
reactive, import { onLoad } from '@dcloudio/uni-app';
ref
} from 'vue';
import {
onLoad
} from '@dcloudio/uni-app';
import AddressSelection from '@/pages/order/addressSelection.vue'; import AddressSelection from '@/pages/order/addressSelection.vue';
import sheep from '@/sheep'; import sheep from '@/sheep';
import OrderApi from '@/sheep/api/trade/order'; import OrderApi from '@/sheep/api/trade/order';
import CouponApi from '@/sheep/api/promotion/coupon'; import TradeConfigApi from '@/sheep/api/trade/config';
import { import { fen2yuan } from '@/sheep/hooks/useGoods';
fen2yuan
} from '@/sheep/hooks/useGoods';
const state = reactive({ const state = reactive({
orderPayload: {}, orderPayload: {},
@ -164,8 +230,8 @@
const addressState = ref({ const addressState = ref({
addressInfo: {}, // addressInfo: {}, //
deliveryType: 1, // 1 - 2 - deliveryType: 1, // 1-2-
isPickUp: true, // TODO puhui999: isPickUp: true, //
pickUpInfo: {}, // pickUpInfo: {}, //
receiverName: '', // receiverName: '', //
receiverMobile: '', // receiverMobile: '', //
@ -182,7 +248,7 @@
// //
async function onSelectCoupon(couponId) { async function onSelectCoupon(couponId) {
state.orderPayload.couponId = couponId || 0; state.orderPayload.couponId = couponId;
await getOrderInfo(); await getOrderInfo();
state.showCoupon = false; state.showCoupon = false;
} }
@ -216,10 +282,7 @@
// & // &
async function submitOrder() { async function submitOrder() {
const { const { code, data } = await OrderApi.createOrder({
code,
data
} = await OrderApi.createOrder({
items: state.orderPayload.items, items: state.orderPayload.items,
couponId: state.orderPayload.couponId, couponId: state.orderPayload.couponId,
remark: state.orderPayload.remark, remark: state.orderPayload.remark,
@ -250,10 +313,7 @@
// & // &
async function getOrderInfo() { async function getOrderInfo() {
// //
const { const { data, code } = await OrderApi.settlementOrder({
data,
code
} = await OrderApi.settlementOrder({
items: state.orderPayload.items, items: state.orderPayload.items,
couponId: state.orderPayload.couponId, couponId: state.orderPayload.couponId,
deliveryType: addressState.value.deliveryType, deliveryType: addressState.value.deliveryType,
@ -267,38 +327,16 @@
seckillActivityId: state.orderPayload.seckillActivityId, seckillActivityId: state.orderPayload.seckillActivityId,
}); });
if (code !== 0) { if (code !== 0) {
setTimeout(() => {
uni.navigateBack({
delta: 1
})
}, 1500)
return; return;
} }
state.orderInfo = data; state.orderInfo = data;
state.couponInfo = data.coupons;
// //
if (state.orderInfo.address) { if (state.orderInfo.address) {
addressState.value.addressInfo = state.orderInfo.address; addressState.value.addressInfo = state.orderInfo.address;
} }
} }
//
let couponNumber = ref(0)
async function getCoupons() {
const {
code,
data
} = await CouponApi.getMatchCouponList(
state.orderInfo.price.payPrice,
state.orderInfo.items.map((item) => item.spuId),
state.orderPayload.items.map((item) => item.skuId),
state.orderPayload.items.map((item) => item.categoryId),
);
if (code === 0) {
state.couponInfo = data;
couponNumber.value = state.couponInfo.filter(item => item.match).length;
}
}
onLoad(async (options) => { onLoad(async (options) => {
if (!options.data) { if (!options.data) {
sheep.$helper.toast('参数不正确,请检查!'); sheep.$helper.toast('参数不正确,请检查!');
@ -306,7 +344,22 @@
} }
state.orderPayload = JSON.parse(options.data); state.orderPayload = JSON.parse(options.data);
await getOrderInfo(); await getOrderInfo();
await getCoupons(); //
const { data, code } = await TradeConfigApi.getTradeConfig();
if (code === 0) {
addressState.value.isPickUp = data.deliveryPickUpEnabled;
}
});
// 使 watch
watch(addressState, async (newAddress, oldAddress) => {
//
if (
newAddress.addressInfo.id !== oldAddress.addressInfo.id ||
newAddress.deliveryType !== oldAddress.deliveryType
) {
await getOrderInfo();
}
}); });
</script> </script>

View File

@ -45,9 +45,9 @@
</image> </image>
<view class="ss-font-30">{{ formatOrderStatus(state.orderInfo) }}</view> <view class="ss-font-30">{{ formatOrderStatus(state.orderInfo) }}</view>
</view> </view>
<view class="ss-font-26 ss-m-x-20 ss-m-b-70">{{ <view class="ss-font-26 ss-m-x-20 ss-m-b-70">
formatOrderStatusDescription(state.orderInfo) {{ formatOrderStatusDescription(state.orderInfo) }}
}}</view> </view>
</view> </view>
<!-- 收货地址 --> <!-- 收货地址 -->
@ -126,6 +126,9 @@
</view> </view>
</view> </view>
<!-- 自提核销 -->
<PickUpVerify :order-info="state.orderInfo" :systemStore="systemStore" ref="pickUpVerifyRef"></PickUpVerify>
<!-- 订单信息 --> <!-- 订单信息 -->
<view class="notice-box"> <view class="notice-box">
<view class="notice-box__content"> <view class="notice-box__content">
@ -167,11 +170,14 @@
<text class="title">运费</text> <text class="title">运费</text>
<text class="detail">{{ fen2yuan(state.orderInfo.deliveryPrice) }}</text> <text class="detail">{{ fen2yuan(state.orderInfo.deliveryPrice) }}</text>
</view> </view>
<!-- TODO 芋艿优惠劵抵扣积分抵扣 -->
<view class="notice-item ss-flex ss-row-between" v-if="state.orderInfo.couponPrice > 0"> <view class="notice-item ss-flex ss-row-between" v-if="state.orderInfo.couponPrice > 0">
<text class="title">优惠劵金额</text> <text class="title">优惠劵金额</text>
<text class="detail">-¥{{ fen2yuan(state.orderInfo.couponPrice) }}</text> <text class="detail">-¥{{ fen2yuan(state.orderInfo.couponPrice) }}</text>
</view> </view>
<view class="notice-item ss-flex ss-row-between" v-if="state.orderInfo.pointPrice > 0">
<text class="title">积分抵扣</text>
<text class="detail">-¥{{ fen2yuan(state.orderInfo.pointPrice) }}</text>
</view>
<view class="notice-item ss-flex ss-row-between" v-if="state.orderInfo.discountPrice > 0"> <view class="notice-item ss-flex ss-row-between" v-if="state.orderInfo.discountPrice > 0">
<text class="title">活动优惠</text> <text class="title">活动优惠</text>
<text class="detail">¥{{ fen2yuan(state.orderInfo.discountPrice) }}</text> <text class="detail">¥{{ fen2yuan(state.orderInfo.discountPrice) }}</text>
@ -251,7 +257,7 @@
<script setup> <script setup>
import sheep from '@/sheep'; import sheep from '@/sheep';
import { onLoad } from '@dcloudio/uni-app'; import { onLoad } from '@dcloudio/uni-app';
import { reactive } from 'vue'; import { reactive, ref } from 'vue';
import { isEmpty } from 'lodash-es'; import { isEmpty } from 'lodash-es';
import { import {
fen2yuan, fen2yuan,
@ -260,6 +266,8 @@
handleOrderButtons, handleOrderButtons,
} from '@/sheep/hooks/useGoods'; } from '@/sheep/hooks/useGoods';
import OrderApi from '@/sheep/api/trade/order'; import OrderApi from '@/sheep/api/trade/order';
import DeliveryApi from '@/sheep/api/trade/delivery';
import PickUpVerify from '@/pages/order/pickUpVerify.vue';
const statusBarHeight = sheep.$platform.device.statusBarHeight * 2; const statusBarHeight = sheep.$platform.device.statusBarHeight * 2;
const headerBg = sheep.$url.css('/static/img/shop/order/order_bg.png'); const headerBg = sheep.$url.css('/static/img/shop/order/order_bg.png');
@ -270,6 +278,9 @@
comeinType: '', // comeinType: '', //
}); });
// ========== ==========
const systemStore = ref({}); //
// //
const onCopy = () => { const onCopy = () => {
sheep.$helper.copyText(state.orderInfo.no); sheep.$helper.copyText(state.orderInfo.no);
@ -313,7 +324,7 @@
}); });
} }
// TODO //
async function onConfirm(orderId, ignore = false) { async function onConfirm(orderId, ignore = false) {
// //
// todo: // todo:
@ -366,6 +377,7 @@
}, },
}); });
} }
// #endif // #endif
// //
@ -375,6 +387,8 @@
}); });
} }
const pickUpVerifyRef = ref();
async function getOrderDetail(id) { async function getOrderDetail(id) {
// //
let res; let res;
@ -389,6 +403,14 @@
if (res.code === 0) { if (res.code === 0) {
state.orderInfo = res.data; state.orderInfo = res.data;
handleOrderButtons(state.orderInfo); handleOrderButtons(state.orderInfo);
//
if (res.data.pickUpStoreId) {
const { data } = await DeliveryApi.getDeliveryPickUpStore(res.data.pickUpStoreId);
systemStore.value = data || {};
}
if (state.orderInfo.deliveryType === 2 && state.orderInfo.payStatus) {
pickUpVerifyRef.value && pickUpVerifyRef.value.markCode(res.data.pickUpVerifyCode);
}
} else { } else {
sheep.$router.back(); sheep.$router.back();
} }

View File

@ -12,7 +12,7 @@
</swiper> </swiper>
</uni-swiper-dot> </uni-swiper-dot>
<view class="log-card-msg"> <view class="log-card-msg">
<!-- TODO 芋艿优化点展示状态 --> <!-- TODO 芋艿物流优化点展示状态 -->
<!-- <view class="ss-flex ss-m-b-8">--> <!-- <view class="ss-flex ss-m-b-8">-->
<!-- <view>物流状态</view>--> <!-- <view>物流状态</view>-->
<!-- <view class="warning-color">{{ state.info.status_text }}</view>--> <!-- <view class="warning-color">{{ state.info.status_text }}</view>-->
@ -34,7 +34,7 @@
<view v-if="state.tracks.length - 1 !== index" class="line" /> <view v-if="state.tracks.length - 1 !== index" class="line" />
</view> </view>
<view class="log-content-msg"> <view class="log-content-msg">
<!-- TODO 芋艿优化点展示状态 --> <!-- TODO 芋艿物流优化点展示状态 -->
<!-- <view class="log-msg-title ss-m-b-20">--> <!-- <view class="log-msg-title ss-m-b-20">-->
<!-- {{ item.status_text }}--> <!-- {{ item.status_text }}-->
<!-- </view>--> <!-- </view>-->

View File

@ -0,0 +1,261 @@
<template>
<view class='order-details'>
<!-- 自提商品核销 -->
<view v-if="orderInfo.deliveryType === 2 && orderInfo.payStatus" class="writeOff borRadius14">
<view class="title">核销信息</view>
<view class="grayBg flex-center">
<view class="pictrue">
<image
v-if="!!painterImageUrl"
:src="painterImageUrl"
:style="{width: `${state.qrcodeSize}px`, height: `${state.qrcodeSize}px`}"
:show-menu-by-longpress="true"
/>
</view>
</view>
<view class="gear">
<image :src="sheep.$url.static('/static/images/writeOff.png', 'local')"></image>
</view>
<view class="num">{{ orderInfo.pickUpVerifyCode }}</view>
<view class="rules">
<!-- TODO puhui999: 需要后端放回使用 receiveTime 即可 -->
<!-- <view class="item">-->
<!-- <view class="rulesTitle flex flex-wrap align-center">-->
<!-- 核销时间-->
<!-- </view>-->
<!-- <view class="info">-->
<!-- 每日-->
<!-- <text class="time">2020-2-+52</text>-->
<!-- </view>-->
<!-- </view>-->
<view class="item">
<view class="rulesTitle flex flex-wrap align-center">
<text class="iconfont icon-shuoming1"></text>
使用说明
</view>
<view class="info">可将二维码出示给店员扫描或提供数字核销码</view>
</view>
</view>
</view>
<view v-if="orderInfo.deliveryType === 2" class="map flex flex-wrap align-center ss-row-between borRadius14">
<view>自提地址信息</view>
<view class="place cart-color flex flex-wrap flex-center" @tap="showMaoLocation">
查看位置
</view>
</view>
<!-- 海报画板默认隐藏只用来生成海报生成方式为主动调用 -->
<l-painter
v-if="showPainter"
isCanvasToTempFilePath
pathType="url"
@success="setPainterImageUrl"
hidden
ref="painterRef"
/>
</view>
</template>
<script setup>
import sheep from '@/sheep';
import { reactive, ref } from 'vue';
const props = defineProps({
orderInfo: {
type: Object,
default() {},
},
systemStore:{
type: Object,
default() {},
}
});
const state = reactive({
qrcodeSize: 145
})
/**
* 打开地图
*/
const showMaoLocation = () => {
console.log(props.systemStore);
if (!props.systemStore.latitude || !props.systemStore.longitude) {
sheep.$helper.toast('缺少经纬度信息无法查看地图!');
return
}
uni.openLocation({
latitude: props.systemStore.latitude,
longitude: props.systemStore.longitude,
scale: 8,
name: props.systemStore.name,
address: props.systemStore.areaName + props.systemStore.detailAddress,
});
}
/**
* 拨打电话
*/
const makePhone = () => {
uni.makePhoneCall({
phoneNumber: props.systemStore.phone
})
}
const painterRef = ref(); //
const painterImageUrl = ref(); // url
const showPainter = ref(true)
//
const renderPoster = async (poster) => {
await painterRef.value.render(poster);
};
//
const setPainterImageUrl = (path) => {
painterImageUrl.value = path;
showPainter.value = false
};
/**
* 生成核销二维码
*/
const markCode = (text) => {
renderPoster({
css: {
width: `${state.qrcodeSize}px`,
height: `${state.qrcodeSize}px`
},
views:[
{
type: 'qrcode',
text: text,
css: {
width: `${state.qrcodeSize}px`,
height: `${state.qrcodeSize}px`
}
}
]
})
}
defineExpose({
markCode
})
</script>
<style scoped lang="scss">
// TODO puhui999: bug
.borRadius14 {
border-radius: 14rpx !important;
}
.cart-color {
color: #E93323 !important;
border: 1px solid #E93323 !important
}
.order-details{
border-radius: 10rpx;
margin: 0 20rpx 20rpx 20rpx;
}
.order-details .writeOff {
background-color: #fff;
margin-top: 15rpx;
padding-bottom: 50rpx;
}
.order-details .writeOff .title {
font-size: 30rpx;
color: #282828;
height: 87rpx;
border-bottom: 1px solid #f0f0f0;
padding: 0 24rpx;
line-height: 87rpx;
}
.order-details .writeOff .grayBg {
background-color: #f2f5f7;
width: 590rpx;
height: 384rpx;
border-radius: 20rpx 20rpx 0 0;
margin: 50rpx auto 0 auto;
padding-top: 55rpx;
}
.order-details .writeOff .grayBg .pictrue {
width: 290rpx;
height: 290rpx;
}
.order-details .writeOff .grayBg .pictrue image {
width: 100%;
height: 100%;
}
.order-details .writeOff .gear {
width: 590rpx;
height: 30rpx;
margin: 0 auto;
}
.order-details .writeOff .gear image {
width: 100%;
height: 100%;
}
.order-details .writeOff .num {
background-color: #f0c34c;
width: 590rpx;
height: 84rpx;
color: #282828;
font-size: 48rpx;
margin: 0 auto;
border-radius: 0 0 20rpx 20rpx;
text-align: center;
padding-top: 4rpx;
}
.order-details .writeOff .rules {
margin: 46rpx 30rpx 0 30rpx;
border-top: 1px solid #f0f0f0;
padding-top: 10rpx;
}
.order-details .writeOff .rules .item {
margin-top: 20rpx;
}
.order-details .writeOff .rules .item .rulesTitle {
font-size: 28rpx;
color: #282828;
}
.order-details .writeOff .rules .item .rulesTitle .iconfont {
font-size: 30rpx;
color: #333;
margin-right: 8rpx;
margin-top: 5rpx;
}
.order-details .writeOff .rules .item .info {
font-size: 28rpx;
color: #999;
margin-top: 7rpx;
}
.order-details .writeOff .rules .item .info .time {
margin-left: 20rpx;
}
.order-details .map {
height: 86rpx;
font-size: 30rpx;
color: #282828;
line-height: 86rpx;
border-bottom: 1px solid #f0f0f0;
margin-top: 15rpx;
background-color: #fff;
padding: 0 24rpx;
}
.order-details .map .place {
font-size: 26rpx;
width: 176rpx;
height: 50rpx;
border-radius: 25rpx;
line-height: 50rpx;
text-align: center;
}
</style>

View File

@ -174,6 +174,12 @@
return return
} }
state.payMethods = getPayMethods(data) state.payMethods = getPayMethods(data)
state.payMethods.find(item => {
if (item.value && !item.disabled) {
state.payment = item.value;
return true;
}
});
} }
onLoad((options) => { onLoad((options) => {

View File

@ -39,7 +39,6 @@
<button class="check-btn ss-reset-button" v-if="payResult === 'success'" @tap="onOrder"> <button class="check-btn ss-reset-button" v-if="payResult === 'success'" @tap="onOrder">
查看订单 查看订单
</button> </button>
<!-- TODO 芋艿拼团接入 -->
<button <button
class="check-btn ss-reset-button" class="check-btn ss-reset-button"
v-if="payResult === 'success' && state.tradeOrder.type === 3" v-if="payResult === 'success' && state.tradeOrder.type === 3"

View File

@ -49,7 +49,7 @@
} }
} }
onLoad(() => { onLoad(() => {
// TODO 使 faq // TODO 使 faq
if (true) { if (true) {
sheep.$router.go('/pages/public/richtext', { sheep.$router.go('/pages/public/richtext', {
title: '常见问题', title: '常见问题',

View File

@ -39,8 +39,8 @@
</template> </template>
<script setup> <script setup>
import { reactive, onBeforeMount } from 'vue'; import { onBeforeMount, reactive } from 'vue';
import { onShow } from '@dcloudio/uni-app'; import { onShow, onLoad } from '@dcloudio/uni-app';
import sheep from '@/sheep'; import sheep from '@/sheep';
import { isEmpty } from 'lodash-es'; import { isEmpty } from 'lodash-es';
import AreaApi from '@/sheep/api/system/area'; import AreaApi from '@/sheep/api/system/area';
@ -49,10 +49,14 @@
const state = reactive({ const state = reactive({
list: [], // list: [], //
loading: true, loading: true,
openType: '', //
}); });
// //
const onSelect = (addressInfo) => { const onSelect = (addressInfo) => {
if (state.openType !== 'select'){ //
return
}
uni.$emit('SELECT_ADDRESS', { uni.$emit('SELECT_ADDRESS', {
addressInfo, addressInfo,
}); });
@ -60,7 +64,6 @@
}; };
// //
// TODO
function importWechatAddress() { function importWechatAddress() {
let wechatAddress = {}; let wechatAddress = {};
// #ifdef MP // #ifdef MP
@ -110,6 +113,12 @@
// #endif // #endif
} }
onLoad((option) => {
if (option.type) {
state.openType = option.type;
}
});
onShow(async () => { onShow(async () => {
state.list = (await AddressApi.getAddressList()).data; state.list = (await AddressApi.getAddressList()).data;
state.loading = false; state.loading = false;

View File

@ -0,0 +1,282 @@
<template>
<s-layout title="选择自提门店" :bgStyle="{ color: '#FFF' }">
<view class="storeBox" ref="container">
<view
class="storeBox-box"
v-for="(item, index) in state.storeList"
:key="index"
@tap="checked(item)"
>
<view class="store-img">
<image :src="item.logo" class="img" />
</view>
<view class="store-cent-left">
<view class="store-name">{{ item.name }}</view>
<view class="store-address line1">
{{ item.areaName }}{{ ', ' + item.detailAddress }}
</view>
</view>
<view class="row-right ss-flex-col ss-col-center">
<view>
<!-- #ifdef H5 -->
<a class="store-phone" :href="'tel:' + item.phone">
<view class="iconfont">
<view class="ss-rest-button">
<text class="_icon-forward" />
</view>
</view>
</a>
<!-- #endif -->
<!-- #ifdef MP -->
<view class="store-phone" @click="call(item.phone)">
<view class="iconfont">
<view class="ss-rest-button">
<text class="_icon-forward" />
</view>
</view>
</view>
<!-- #endif -->
</view>
<view class="store-distance ss-flex ss-row-center" @tap.stop="showMaoLocation(item)">
<text class="addressTxt" v-if="item.distance">
距离{{ item.distance.toFixed(2) }}千米
</text>
<text class="addressTxt" v-else></text>
<view class="iconfont">
<view class="ss-rest-button">
<text class="_icon-forward" />
</view>
</view>
</view>
</view>
</view>
</view>
</s-layout>
</template>
<script setup>
import DeliveryApi from '@/sheep/api/trade/delivery';
import { onMounted, reactive } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import sheep from '@/sheep';
const LONGITUDE = 'user_longitude';
const LATITUDE = 'user_latitude';
const state = reactive({
loaded: false,
loading: false,
storeList: [],
system_store: {},
locationShow: false,
user_latitude: 0,
user_longitude: 0,
});
const call = (phone) => {
uni.makePhoneCall({
phoneNumber: phone,
});
};
const selfLocation = () => {
// #ifdef H5
const jsWxSdk = sheep.$platform.useProvider('wechat').jsWxSdk;
if (jsWxSdk.isWechat()) {
jsWxSdk.getLocation((res) => {
state.user_latitude = res.latitude;
state.user_longitude = res.longitude;
uni.setStorageSync(LATITUDE, res.latitude);
uni.setStorageSync(LONGITUDE, res.longitude);
getList();
});
} else {
// #endif
uni.getLocation({
type: 'gcj02',
success: (res) => {
try {
state.user_latitude = res.latitude;
state.user_longitude = res.longitude;
uni.setStorageSync(LATITUDE, res.latitude);
uni.setStorageSync(LONGITUDE, res.longitude);
} catch (e) {
console.error(e);
}
getList();
},
complete: () => {
getList();
},
});
// #ifdef H5
}
// #endif
};
const showMaoLocation = (e) => {
// #ifdef H5
const jsWxSdk = sheep.$platform.useProvider('wechat').jsWxSdk;
if (jsWxSdk.isWechat()) {
jsWxSdk.openLocation({
latitude: Number(e.latitude),
longitude: Number(e.longitude),
name: e.name,
address: `${e.areaName}-${e.detailAddress}`,
});
} else {
// #endif
uni.openLocation({
latitude: Number(e.latitude),
longitude: Number(e.longitude),
name: e.name,
address: `${e.areaName}-${e.detailAddress}`,
success: function () {
console.log('success');
},
});
// #ifdef H5
}
// #endif
};
/**
* 选中门店
*/
const checked = (addressInfo) => {
uni.$emit('SELECT_PICK_UP_INFO', {
addressInfo,
});
sheep.$router.back();
};
/**
* 获取门店列表数据
*/
const getList = async () => {
if (state.loading || state.loaded) {
return;
}
state.loading = true;
const { data, code } = await DeliveryApi.getDeliveryPickUpStoreList({
latitude: state.user_latitude,
longitude: state.user_longitude,
});
if (code !== 0) {
return;
}
state.loading = false;
state.storeList = data;
};
onMounted(() => {
if (state.user_latitude && state.user_longitude) {
getList();
} else {
selfLocation();
getList();
}
});
onLoad(() => {
try {
state.user_latitude = uni.getStorageSync(LATITUDE);
state.user_longitude = uni.getStorageSync(LONGITUDE);
} catch (e) {
console.error(e);
}
});
</script>
<style lang="scss" scoped>
.line1 {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.geoPage {
position: fixed;
width: 100%;
height: 100%;
top: 0;
z-index: 10000;
}
.storeBox {
width: 100%;
background-color: #fff;
padding: 0 30rpx;
}
.storeBox-box {
width: 100%;
height: auto;
display: flex;
align-items: center;
padding: 23rpx 0;
justify-content: space-between;
border-bottom: 1px solid #eee;
}
.store-cent {
display: flex;
align-items: center;
width: 80%;
}
.store-cent-left {
//width: 45%;
flex: 2;
}
.store-img {
flex: 1;
width: 120rpx;
height: 120rpx;
border-radius: 6rpx;
margin-right: 22rpx;
}
.store-img .img {
width: 100%;
height: 100%;
}
.store-name {
color: #282828;
font-size: 30rpx;
margin-bottom: 22rpx;
font-weight: 800;
}
.store-address {
color: #666666;
font-size: 24rpx;
}
.store-phone {
width: 50rpx;
height: 50rpx;
color: #fff;
border-radius: 50%;
display: block;
text-align: center;
line-height: 48rpx;
background-color: #e83323;
margin-bottom: 22rpx;
text-decoration: none;
}
.store-distance {
font-size: 22rpx;
color: #e83323;
}
.iconfont {
font-size: 20rpx;
}
.row-right {
flex: 2;
//display: flex;
//flex-direction: column;
//align-items: flex-end;
//width: 33.5%;
}
</style>

View File

@ -36,7 +36,7 @@
</button> </button>
</uni-datetime-picker> </uni-datetime-picker>
<!-- TODO 芋艿优化 --> <!-- TODO 芋艿钱包优化 -->
<!-- <view class="total-box">--> <!-- <view class="total-box">-->
<!-- <view class="ss-m-b-10">总收入{{ state.pagination.income }}</view>--> <!-- <view class="ss-m-b-10">总收入{{ state.pagination.income }}</view>-->
<!-- <view>总支出{{ -state.pagination.expense }}</view>--> <!-- <view>总支出{{ -state.pagination.expense }}</view>-->

View File

@ -1,14 +0,0 @@
import request from '@/sheep/request';
// TODO 芋艿:暂不支持 socket 聊天
export default {
// 获取聊天token
unifiedToken: () =>
request({
url: 'unifiedToken',
custom: {
showError: false,
showLoading: false,
},
}),
};

View File

@ -1,7 +1,7 @@
import request from '@/sheep/request'; import request from '@/sheep/request';
const ActivityApi = { const ActivityApi = {
// 获得单个商品,近期参与的每个活动 // 获得单个商品,进行中的拼团、秒杀、砍价活动信息
getActivityListBySpuId: (spuId) => { getActivityListBySpuId: (spuId) => {
return request({ return request({
url: '/promotion/activity/list-by-spu-id', url: '/promotion/activity/list-by-spu-id',

View File

@ -2,15 +2,6 @@ import request from '@/sheep/request';
// 拼团 API // 拼团 API
const CombinationApi = { const CombinationApi = {
// 获得拼团活动列表
getCombinationActivityList: (count) => {
return request({
url: '/promotion/combination-activity/list',
method: 'GET',
params: { count },
});
},
// 获得拼团活动分页 // 获得拼团活动分页
getCombinationActivityPage: (params) => { getCombinationActivityPage: (params) => {
return request({ return request({
@ -31,6 +22,17 @@ const CombinationApi = {
}); });
}, },
// 获得拼团活动列表,基于活动编号数组
getCombinationActivityListByIds: (ids) => {
return request({
url: '/promotion/combination-activity/list-by-ids',
method: 'GET',
params: {
ids,
},
});
},
// 获得最近 n 条拼团记录(团长发起的) // 获得最近 n 条拼团记录(团长发起的)
getHeadCombinationRecordList: (activityId, status, count) => { getHeadCombinationRecordList: (activityId, status, count) => {
return request({ return request({
@ -47,9 +49,9 @@ const CombinationApi = {
// 获得我的拼团记录分页 // 获得我的拼团记录分页
getCombinationRecordPage: (params) => { getCombinationRecordPage: (params) => {
return request({ return request({
url: "/promotion/combination-record/page", url: '/promotion/combination-record/page',
method: 'GET', method: 'GET',
params params,
}); });
}, },

View File

@ -79,23 +79,6 @@ const CouponApi = {
}, },
}); });
}, },
// 获得匹配指定商品的优惠劵列表
getMatchCouponList: (price, spuIds, skuIds, categoryIds) => {
return request({
url: '/promotion/coupon/match-list',
method: 'GET',
params: {
price,
spuIds: spuIds.join(','),
skuIds: skuIds.join(','),
categoryIds: categoryIds.join(','),
},
custom: {
showError: false,
showLoading: false, // 避免影响 settlementOrder 结算的结果
},
});
}
}; };
export default CouponApi; export default CouponApi;

View File

@ -1,4 +1,4 @@
import request from "@/sheep/request"; import request from '@/sheep/request';
const SeckillApi = { const SeckillApi = {
// 获得秒杀时间段列表 // 获得秒杀时间段列表
@ -16,6 +16,17 @@ const SeckillApi = {
return request({ url: 'promotion/seckill-activity/page', method: 'GET', params }); return request({ url: 'promotion/seckill-activity/page', method: 'GET', params });
}, },
// 获得秒杀活动列表,基于活动编号数组
getSeckillActivityListByIds: (ids) => {
return request({
url: '/promotion/seckill-activity/list-by-ids',
method: 'GET',
params: {
ids,
},
});
},
/** /**
* 获得秒杀活动明细 * 获得秒杀活动明细
* @param {number} id 秒杀活动编号 * @param {number} id 秒杀活动编号
@ -25,9 +36,9 @@ const SeckillApi = {
return request({ return request({
url: 'promotion/seckill-activity/get-detail', url: 'promotion/seckill-activity/get-detail',
method: 'GET', method: 'GET',
params: { id } params: { id },
}); });
} },
} };
export default SeckillApi; export default SeckillApi;

16
sheep/api/system/dict.js Normal file
View File

@ -0,0 +1,16 @@
import request from '@/sheep/request';
const DictApi = {
// 根据字典类型查询字典数据信息
getDictDataListByType: (type) => {
return request({
url: `/system/dict-data/type`,
method: 'GET',
params: {
type,
},
});
},
};
export default DictApi;

View File

@ -7,7 +7,25 @@ const DeliveryApi = {
url: `/trade/delivery/express/list`, url: `/trade/delivery/express/list`,
method: 'get', method: 'get',
}); });
} },
// 获得自提门店列表
getDeliveryPickUpStoreList: (params) => {
return request({
url: `/trade/delivery/pick-up-store/list`,
method: 'GET',
params,
});
},
// 获得自提门店
getDeliveryPickUpStore: (id) => {
return request({
url: `/trade/delivery/pick-up-store/get`,
method: 'GET',
params: {
id,
},
});
},
}; };
export default DeliveryApi; export default DeliveryApi;

View File

@ -1,4 +1,5 @@
import request from '@/sheep/request'; import request from '@/sheep/request';
import { isEmpty } from '@/sheep/helper/utils';
const OrderApi = { const OrderApi = {
// 计算订单信息 // 计算订单信息
@ -13,6 +14,15 @@ const OrderApi = {
if (!(data.addressId > 0)) { if (!(data.addressId > 0)) {
delete data2.addressId; delete data2.addressId;
} }
if (!(data.pickUpStoreId > 0)) {
delete data2.pickUpStoreId;
}
if (isEmpty(data.receiverName)) {
delete data2.receiverName;
}
if (isEmpty(data.receiverMobile)) {
delete data2.receiverMobile;
}
if (!(data.combinationActivityId > 0)) { if (!(data.combinationActivityId > 0)) {
delete data2.combinationActivityId; delete data2.combinationActivityId;
} }

View File

@ -10,7 +10,11 @@
/> />
<!-- 2. 短信登录 smsLogin --> <!-- 2. 短信登录 smsLogin -->
<sms-login v-if="authType === 'smsLogin'" :agreeStatus="state.protocol" @onConfirm="onConfirm" /> <sms-login
v-if="authType === 'smsLogin'"
:agreeStatus="state.protocol"
@onConfirm="onConfirm"
/>
<!-- 3. 忘记密码 resetPassword--> <!-- 3. 忘记密码 resetPassword-->
<reset-password v-if="authType === 'resetPassword'" /> <reset-password v-if="authType === 'resetPassword'" />
@ -32,7 +36,11 @@
<!-- 7.1 微信小程序的快捷登录 --> <!-- 7.1 微信小程序的快捷登录 -->
<view v-if="sheep.$platform.name === 'WechatMiniProgram'" class="ss-flex register-box"> <view v-if="sheep.$platform.name === 'WechatMiniProgram'" class="ss-flex register-box">
<view class="register-title">还没有账号?</view> <view class="register-title">还没有账号?</view>
<button class="ss-reset-button login-btn" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber"> <button
class="ss-reset-button login-btn"
open-type="getPhoneNumber"
@getphonenumber="getPhoneNumber"
>
快捷登录 快捷登录
</button> </button>
<view class="circle" /> <view class="circle" />
@ -81,13 +89,9 @@
/> />
<view class="agreement-text ss-flex ss-col-center ss-m-l-8"> <view class="agreement-text ss-flex ss-col-center ss-m-l-8">
我已阅读并遵守 我已阅读并遵守
<view class="tcp-text" @tap.stop="onProtocol('用户协议')"> <view class="tcp-text" @tap.stop="onProtocol('用户协议')"> 用户协议 </view>
用户协议
</view>
<view class="agreement-text"></view> <view class="agreement-text"></view>
<view class="tcp-text" @tap.stop="onProtocol('隐私协议')"> <view class="tcp-text" @tap.stop="onProtocol('隐私协议')"> 隐私协议 </view>
隐私协议
</view>
</view> </view>
</label> </label>
</view> </view>
@ -107,8 +111,6 @@
import mpAuthorization from './components/mp-authorization.vue'; import mpAuthorization from './components/mp-authorization.vue';
import { closeAuthModal, showAuthModal } from '@/sheep/hooks/useModal'; import { closeAuthModal, showAuthModal } from '@/sheep/hooks/useModal';
const appInfo = computed(() => sheep.$store('app').info);
const modalStore = sheep.$store('modal'); const modalStore = sheep.$store('modal');
// //
const authType = computed(() => modalStore.auth); const authType = computed(() => modalStore.auth);
@ -152,7 +154,13 @@
} }
const loginRes = await sheep.$platform.useProvider(provider).login(); const loginRes = await sheep.$platform.useProvider(provider).login();
if (loginRes) { if (loginRes) {
const userInfo = await sheep.$store('user').getInfo();
closeAuthModal(); closeAuthModal();
//
if (userInfo.avatar && userInfo.nickname) {
return;
}
// //
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
showAuthModal('mpAuthorization'); showAuthModal('mpAuthorization');

View File

@ -9,7 +9,7 @@
<!-- 基础组件列表导航 --> <!-- 基础组件列表导航 -->
<s-menu-list v-if="type === 'MenuList'" :data="data" /> <s-menu-list v-if="type === 'MenuList'" :data="data" />
<!-- 基础组件宫格导航 --> <!-- 基础组件宫格导航 -->
<s-menu-grid v-if="type === 'MenuGrid'" :data="data" /> <s-menu-grid v-if="type === 'MenuGrid'" :data="data" :styles="styles" />
<!-- 基础组件弹窗广告 --> <!-- 基础组件弹窗广告 -->
<s-popup-image v-if="type === 'Popover'" :data="data" /> <s-popup-image v-if="type === 'Popover'" :data="data" />
<!-- 基础组件悬浮按钮 --> <!-- 基础组件悬浮按钮 -->
@ -47,13 +47,13 @@
<s-richtext-block v-if="type === 'PromotionArticle'" :data="data" :styles="styles" /> <s-richtext-block v-if="type === 'PromotionArticle'" :data="data" :styles="styles" />
<!-- 用户组件用户卡片 --> <!-- 用户组件用户卡片 -->
<s-user-card v-if="type === 'UserCard'" /> <s-user-card v-if="type === 'UserCard'" :data="data" :styles="styles" />
<!-- 用户组件用户订单 --> <!-- 用户组件用户订单 -->
<s-order-card v-if="type === 'UserOrder'" :data="data" /> <s-order-card v-if="type === 'UserOrder'" :data="data" :styles="styles" />
<!-- 用户组件用户资产 --> <!-- 用户组件用户资产 -->
<s-wallet-card v-if="type === 'UserWallet'" /> <s-wallet-card v-if="type === 'UserWallet'" :data="data" :styles="styles" />
<!-- 用户组件用户卡券 --> <!-- 用户组件用户卡券 -->
<s-coupon-card v-if="type === 'UserCoupon'" /> <s-coupon-card v-if="type === 'UserCoupon'" :data="data" :styles="styles" />
</view> </view>
</template> </template>

View File

@ -1,39 +1,20 @@
<!-- 装修营销组件优惠券 --> <!-- 装修营销组件优惠券 -->
<template> <template>
<scroll-view class="scroll-box" scroll-x scroll-anchoring> <scroll-view class="scroll-box" scroll-x scroll-anchoring :style="[bgStyle, { marginLeft: `${data.space}px` }]">
<view class="coupon-box ss-flex"> <view class="coupon-box ss-flex" :style="couponList.length === 2 ? couponBoxStyleTwo : couponBoxStyleNormal">
<view <view class="coupon-item" :style="[couponBg, { marginLeft: `${data.space}px` }]"
class="coupon-item" v-for="(item, index) in couponList" :key="index">
:style="[couponBg, { marginLeft: `${data.space}px` }]" <su-coupon :size="SIZE_LIST[columns - 1]" :textColor="data.textColor" background="" :couponId="item.id"
v-for="(item, index) in couponList" :title="item.name" :type="formatCouponDiscountType(item)" :value="formatCouponDiscountValue(item)"
:key="index" :sellBy="formatValidityType(item)">
>
<su-coupon
:size="SIZE_LIST[columns - 1]"
:textColor="data.textColor"
background=""
:couponId="item.id"
:title="item.name"
:type="formatCouponDiscountType(item)"
:value="formatCouponDiscountValue(item)"
:sellBy="formatValidityType(item)"
>
<template v-slot:btn> <template v-slot:btn>
<!-- 两列时领取按钮坚排 --> <!-- 两列时领取按钮坚排 -->
<button <button v-if="columns === 2" @click.stop="onGetCoupon(item.id)"
v-if="columns === 2" class="ss-reset-button card-btn vertical" :style="[btnStyles]">
@click.stop="onGetCoupon(item.id)"
class="ss-reset-button card-btn vertical"
:style="[btnStyles]"
>
<view class="btn-text">立即领取</view> <view class="btn-text">立即领取</view>
</button> </button>
<button <button v-else class="ss-reset-button card-btn" :style="[btnStyles]"
v-else @click.stop="onGetCoupon(item.id)">
class="ss-reset-button card-btn"
:style="[btnStyles]"
@click.stop="onGetCoupon(item.id)"
>
立即领取 立即领取
</button> </button>
</template> </template>
@ -46,9 +27,19 @@
<script setup> <script setup>
import sheep from '@/sheep'; import sheep from '@/sheep';
import CouponApi from '@/sheep/api/promotion/coupon'; import CouponApi from '@/sheep/api/promotion/coupon';
import { ref, onMounted } from 'vue'; import {
import { CouponTemplateValidityTypeEnum, PromotionDiscountTypeEnum } from "@/sheep/util/const"; ref,
import { floatToFixed2, formatDate } from "@/sheep/util"; onMounted,
computed
} from 'vue';
import {
CouponTemplateValidityTypeEnum,
PromotionDiscountTypeEnum
} from "@/sheep/util/const";
import {
floatToFixed2,
formatDate
} from "@/sheep/util";
const props = defineProps({ const props = defineProps({
data: { data: {
@ -60,7 +51,10 @@
default: () => ({}), default: () => ({}),
}, },
}); });
const { columns, button } = props.data; const {
columns,
button
} = props.data;
const SIZE_LIST = ['lg', 'md', 'xs'] const SIZE_LIST = ['lg', 'md', 'xs']
const couponBg = { const couponBg = {
background: `url(${sheep.$url.cdn(props.data.bgImg)}) no-repeat top center / 100% 100%`, background: `url(${sheep.$url.cdn(props.data.bgImg)}) no-repeat top center / 100% 100%`,
@ -69,7 +63,30 @@
background: button.bgColor, background: button.bgColor,
color: button.color, color: button.color,
}; };
//
const couponBoxStyleNormal = {
'display': 'flex',
'justify-content': 'space-between'
};
//
const couponBoxStyleTwo = {
'display': 'flex',
'justify-content': 'space-around'
};
//
const bgStyle = computed(() => {
// props.styles
const {
bgType,
bgImg,
bgColor
} = props.styles;
// bgType
return {
background: bgType === 'img' ? `url(${bgImg}) no-repeat top center / 100% 100%` : bgColor
};
});
// //
const formatCouponDiscountType = (coupon) => { const formatCouponDiscountType = (coupon) => {
if (coupon.discountType === PromotionDiscountTypeEnum.PRICE.type) { if (coupon.discountType === PromotionDiscountTypeEnum.PRICE.type) {
@ -106,7 +123,10 @@
const couponList = ref([]); const couponList = ref([]);
// //
async function onGetCoupon(id) { async function onGetCoupon(id) {
const { error, msg } = await CouponApi.takeCoupon(id); const {
error,
msg
} = await CouponApi.takeCoupon(id);
if (error === 0) { if (error === 0) {
uni.showToast({ uni.showToast({
title: msg, title: msg,
@ -117,7 +137,9 @@
await getCouponTemplateList() await getCouponTemplateList()
} }
const getCouponTemplateList = async () => { const getCouponTemplateList = async () => {
const { data } = await CouponApi.getCouponTemplateListByIds(props.data.couponIds.join(',')); const {
data
} = await CouponApi.getCouponTemplateListByIds(props.data.couponIds.join(','));
couponList.value = data; couponList.value = data;
} }
onMounted(() => { onMounted(() => {
@ -132,6 +154,7 @@
border-radius: 25rpx; border-radius: 25rpx;
font-size: 24rpx; font-size: 24rpx;
line-height: 50rpx; line-height: 50rpx;
&.vertical { &.vertical {
width: 50rpx; width: 50rpx;
height: 140rpx; height: 140rpx;
@ -144,6 +167,7 @@
} }
} }
} }
.coupon-item { .coupon-item {
&:nth-of-type(1) { &:nth-of-type(1) {
margin-left: 0 !important; margin-left: 0 !important;

View File

@ -1,6 +1,6 @@
<!-- 装修用户组件用户卡券 --> <!-- 装修用户组件用户卡券 -->
<template> <template>
<view class="ss-coupon-menu-wrap ss-flex ss-col-center"> <view class="ss-coupon-menu-wrap ss-flex ss-col-center" :style="[bgStyle, { marginLeft: `${data.space}px` }]">
<view class="menu-item ss-flex-col ss-row-center ss-col-center" v-for="item in props.list" :key="item.title" <view class="menu-item ss-flex-col ss-row-center ss-col-center" v-for="item in props.list" :key="item.title"
@tap="sheep.$router.go(item.path, { type: item.type })" @tap="sheep.$router.go(item.path, { type: item.type })"
:class="item.type === 'all' ? 'menu-wallet' : 'ss-flex-1'"> :class="item.type === 'all' ? 'menu-wallet' : 'ss-flex-1'">
@ -15,6 +15,7 @@
* 装修组件 - 优惠券菜单 * 装修组件 - 优惠券菜单
*/ */
import sheep from '@/sheep'; import sheep from '@/sheep';
import { computed } from 'vue';
// //
const props = defineProps({ const props = defineProps({
@ -52,6 +53,28 @@
]; ];
}, },
}, },
//
data: {
type: Object,
default: () => ({}),
},
//
styles: {
type: Object,
default: () => ({}),
},
});
//
const bgStyle = computed(() => {
// props.styles
const { bgType, bgImg, bgColor } = props.styles;
// bgType
return {
background: bgType === 'img'
? `url(${bgImg}) no-repeat top center / 100% 100%`
: bgColor
};
}); });
</script> </script>

View File

@ -42,25 +42,17 @@
> >
有效期领取后 {{ data.fixedEndTerm }} 天内可用 有效期领取后 {{ data.fixedEndTerm }} 天内可用
</view> </view>
<view <view class="sellby-text" :class="isDisable ? 'disabled-color' : 'subtitle-color'" v-else>
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') }}
{{ sheep.$helper.timeFormat(data.validEndTime, 'yyyy-mm-dd') }} {{ sheep.$helper.timeFormat(data.validEndTime, 'yyyy-mm-dd') }}
</view> </view>
<view <view class="value-enough" :class="isDisable ? 'disabled-color' : 'subtitle-color'">
class="value-enough"
:class="isDisable ? 'disabled-color' : 'subtitle-color'"
>
{{ fen2yuan(data.usePrice) }} 可用 {{ fen2yuan(data.usePrice) }} 可用
</view> </view>
</view> </view>
</view> </view>
</view> </view>
<!-- TODO 芋艿可优化增加优惠劵的描述 -->
<view class="desc ss-flex ss-row-between"> <view class="desc ss-flex ss-row-between">
<view> <view>
<view class="desc-title">{{ data.description }}</view> <view class="desc-title">{{ data.description }}</view>
@ -76,17 +68,15 @@
</template> </template>
<script setup> <script setup>
import { computed, reactive } from 'vue'; import { computed } from 'vue';
import { fen2yuan } from '../../hooks/useGoods'; import { fen2yuan } from '../../hooks/useGoods';
import sheep from '../../index'; import sheep from '../../index';
const state = reactive({});
const isDisable = computed(() => { const isDisable = computed(() => {
if (props.type === 'coupon') { if (props.type === 'coupon') {
return false; return false;
} }
return props.data.status !== 1; return props.disabled;
}); });
// //

View File

@ -16,8 +16,12 @@
:scroll-with-animation="false" :scroll-with-animation="false"
:enable-back-to-top="true" :enable-back-to-top="true"
> >
<!--可使用的优惠券区域-->
<view class="subtitle ss-m-l-20">可使用优惠券</view> <view class="subtitle ss-m-l-20">可使用优惠券</view>
<view v-for="(item, index) in state.couponInfo" :key="index"> <view
v-for="(item, index) in state.couponInfo.filter((coupon) => coupon.match)"
:key="index"
>
<s-coupon-list :data="item" type="user" :disabled="false"> <s-coupon-list :data="item" type="user" :disabled="false">
<template #default> <template #default>
<label class="ss-flex ss-col-center" @tap="radioChange(item.id)"> <label class="ss-flex ss-col-center" @tap="radioChange(item.id)">
@ -31,19 +35,18 @@
</template> </template>
</s-coupon-list> </s-coupon-list>
</view> </view>
<!-- TODO 芋艿未来接口需要支持下 <!--不可使用的优惠券区域-->
<view class="subtitle ss-m-t-40 ss-m-l-20">不可使用优惠券</view> <view class="subtitle ss-m-t-40 ss-m-l-20">不可使用优惠券</view>
<view v-for="item in state.couponInfo.cannot_use" :key="item.id"> <view v-for="item in state.couponInfo.filter((coupon) => !coupon.match)" :key="item.id">
<s-coupon-list :data="item" type="user" :disabled="true"> <s-coupon-list :data="item" type="user" :disabled="true">
<template v-slot:reason> <template v-slot:reason>
<view class="ss-flex ss-m-t-24"> <view class="ss-flex ss-m-t-24">
<view class="reason-title"> 不可用原因</view> <view class="reason-title"> 不可用原因</view>
<view class="reason-desc">{{ item.cannot_use_msg }}</view> <view class="reason-desc">{{ item.mismatchReason || '未达到使用门槛' }}</view>
</view> </view>
</template> </template>
</s-coupon-list> </s-coupon-list>
</view> </view>
-->
</scroll-view> </scroll-view>
</view> </view>
<view class="modal-footer ss-flex"> <view class="modal-footer ss-flex">
@ -55,7 +58,8 @@
import { computed, reactive } from 'vue'; import { computed, reactive } from 'vue';
const props = defineProps({ const props = defineProps({
modelValue: { // modelValue: {
//
type: Object, type: Object,
default() {}, default() {},
}, },
@ -69,13 +73,13 @@
const state = reactive({ const state = reactive({
couponInfo: computed(() => props.modelValue), // couponInfo: computed(() => props.modelValue), //
couponId: 0, // couponId: undefined, //
}); });
// //
function radioChange(couponId) { function radioChange(couponId) {
if (state.couponId === couponId) { if (state.couponId === couponId) {
state.couponId = 0; state.couponId = undefined;
} else { } else {
state.couponId = couponId; state.couponId = couponId;
} }
@ -84,7 +88,7 @@
// //
const onConfirm = () => { const onConfirm = () => {
emits('confirm', state.couponId); emits('confirm', state.couponId);
} };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
:deep() { :deep() {
@ -96,25 +100,30 @@
.model-box { .model-box {
height: 60vh; height: 60vh;
} }
.title { .title {
font-size: 36rpx; font-size: 36rpx;
height: 80rpx; height: 80rpx;
font-weight: bold; font-weight: bold;
color: #333333; color: #333333;
} }
.subtitle { .subtitle {
font-size: 26rpx; font-size: 26rpx;
font-weight: 500; font-weight: 500;
color: #333333; color: #333333;
} }
.model-content { .model-content {
height: 54vh; height: 54vh;
} }
.modal-footer { .modal-footer {
width: 100%; width: 100%;
height: 120rpx; height: 120rpx;
background: #fff; background: #fff;
} }
.confirm-btn { .confirm-btn {
width: 710rpx; width: 710rpx;
margin-left: 20rpx; margin-left: 20rpx;
@ -123,12 +132,14 @@
border-radius: 40rpx; border-radius: 40rpx;
color: #fff; color: #fff;
} }
.reason-title { .reason-title {
font-weight: 600; font-weight: 600;
font-size: 20rpx; font-size: 20rpx;
line-height: 26rpx; line-height: 26rpx;
color: #ff0003; color: #ff0003;
} }
.reason-desc { .reason-desc {
font-weight: 600; font-weight: 600;
font-size: 20rpx; font-size: 20rpx;

View File

@ -77,7 +77,7 @@
}); });
const navList = computed(() => { const navList = computed(() => {
// #ifdef MP // #ifdef MP
return props.data.mapCells || []; return props.data.mpCells || [];
// #endif // #endif
return props.data.otherCells || []; return props.data.otherCells || [];
}); });
@ -119,9 +119,10 @@
background: background:
props.data.bgType === 'img' && props.data.bgImg props.data.bgType === 'img' && props.data.bgImg
? `url(${sheep.$url.cdn(props.data.bgImg)}) no-repeat top center / 100% 100%` ? `url(${sheep.$url.cdn(props.data.bgImg)}) no-repeat top center / 100% 100%`
: props.data.bgColor : props.data.bgColor,
}; };
}); });
// //
function onClickLeft() { function onClickLeft() {
if (hasHistory) { if (hasHistory) {
@ -130,6 +131,7 @@
sheep.$router.go('/pages/index/index'); sheep.$router.go('/pages/index/index');
} }
} }
// //
function onClickRight() { function onClickRight() {
showMenuTools(); showMenuTools();
@ -147,44 +149,53 @@
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
} }
.nav-icon { .nav-icon {
position: absolute; position: absolute;
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
left: 20rpx; left: 20rpx;
.inner-icon-box { .inner-icon-box {
border: 1px solid rgba(#fff, 0.4); border: 1px solid rgba(#fff, 0.4);
background: none !important; background: none !important;
} }
.icon-box { .icon-box {
background: #ffffff; background: #ffffff;
box-shadow: 0px 0px 4rpx rgba(51, 51, 51, 0.08), box-shadow: 0px 0px 4rpx rgba(51, 51, 51, 0.08), 0px 4rpx 6rpx 2rpx rgba(102, 102, 102, 0.12);
0px 4rpx 6rpx 2rpx rgba(102, 102, 102, 0.12);
border-radius: 30rpx; border-radius: 30rpx;
width: 134rpx; width: 134rpx;
height: 56rpx; height: 56rpx;
margin-left: 8rpx; margin-left: 8rpx;
.line { .line {
width: 2rpx; width: 2rpx;
height: 24rpx; height: 24rpx;
background: #e5e5e7; background: #e5e5e7;
} }
.sicon-back { .sicon-back {
font-size: 32rpx; font-size: 32rpx;
} }
.sicon-home { .sicon-home {
font-size: 32rpx; font-size: 32rpx;
} }
.sicon-more { .sicon-more {
font-size: 32rpx; font-size: 32rpx;
} }
.icon-button { .icon-button {
width: 67rpx; width: 67rpx;
height: 56rpx; height: 56rpx;
&-left:hover { &-left:hover {
background: rgba(0, 0, 0, 0.16); background: rgba(0, 0, 0, 0.16);
border-radius: 30rpx 0px 0px 30rpx; border-radius: 30rpx 0px 0px 30rpx;
} }
&-right:hover { &-right:hover {
background: rgba(0, 0, 0, 0.16); background: rgba(0, 0, 0, 0.16);
border-radius: 0px 30rpx 30rpx 0px; border-radius: 0px 30rpx 30rpx 0px;

View File

@ -3,7 +3,10 @@
<!-- 商品卡片 --> <!-- 商品卡片 -->
<view> <view>
<!-- 布局1. 单列大图上图下内容--> <!-- 布局1. 单列大图上图下内容-->
<view v-if="layoutType === LayoutTypeEnum.ONE_COL_BIG_IMG && state.goodsList.length" class="goods-sl-box"> <view
v-if="layoutType === LayoutTypeEnum.ONE_COL_BIG_IMG && state.goodsList.length"
class="goods-sl-box"
>
<view <view
class="goods-box" class="goods-box"
v-for="item in state.goodsList" v-for="item in state.goodsList"
@ -100,7 +103,10 @@
</view> </view>
<!-- 布局3. 单列小图左图右内容 --> <!-- 布局3. 单列小图左图右内容 -->
<view v-if="layoutType === LayoutTypeEnum.ONE_COL_SMALL_IMG && state.goodsList.length" class="goods-lg-box"> <view
v-if="layoutType === LayoutTypeEnum.ONE_COL_SMALL_IMG && state.goodsList.length"
class="goods-lg-box"
>
<view <view
class="goods-box" class="goods-box"
:style="[{ marginBottom: data.space + 'px' }]" :style="[{ marginBottom: data.space + 'px' }]"
@ -147,7 +153,7 @@
TWO_COL: 'twoCol', TWO_COL: 'twoCol',
// //
ONE_COL_SMALL_IMG: 'oneColSmallImg', ONE_COL_SMALL_IMG: 'oneColSmallImg',
} };
const state = reactive({ const state = reactive({
goodsList: [], goodsList: [],
@ -157,16 +163,16 @@
const props = defineProps({ const props = defineProps({
data: { data: {
type: Object, type: Object,
default() {}, default: () => ({}),
}, },
styles: { styles: {
type: Object, type: Object,
default() {}, default: () => ({}),
}, },
}); });
const { layoutType, btnBuy, spuIds } = props.data ?? {}; const { layoutType, btnBuy, spuIds } = props.data || {};
const { marginLeft, marginRight } = props.styles ?? {}; const { marginLeft, marginRight } = props.styles || {};
// //
const buyStyle = computed(() => { const buyStyle = computed(() => {
@ -215,6 +221,7 @@
// //
count++; count++;
} }
//endregion //endregion
/** /**
@ -298,11 +305,13 @@
.goods-list-box { .goods-list-box {
width: 50%; width: 50%;
box-sizing: border-box; box-sizing: border-box;
.left-list { .left-list {
&:nth-last-child(1) { &:nth-last-child(1) {
margin-bottom: 0 !important; margin-bottom: 0 !important;
} }
} }
.right-list { .right-list {
&:nth-last-child(1) { &:nth-last-child(1) {
margin-bottom: 0 !important; margin-bottom: 0 !important;

View File

@ -2,29 +2,38 @@
<template> <template>
<view class="ss-goods-wrap"> <view class="ss-goods-wrap">
<!-- xs卡片横向紧凑型一行放两个图片左内容右边 --> <!-- xs卡片横向紧凑型一行放两个图片左内容右边 -->
<view v-if="size === 'xs'" class="xs-goods-card ss-flex ss-col-stretch" :style="[elStyles]" @tap="onClick"> <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"> <view v-if="tagStyle.show" class="tag-icon-box">
<image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image> <image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image>
</view> </view>
<image class="xs-img-box" :src="sheep.$url.cdn(data.image || data.picUrl)" mode="aspectFit"></image> <image
<view v-if="goodsFields.title?.show || goodsFields.name?.show || goodsFields.price?.show" class="xs-img-box"
class="xs-goods-content ss-flex-col ss-row-around"> :src="sheep.$url.cdn(data.image || data.picUrl)"
<view v-if="goodsFields.title?.show || goodsFields.name?.show" class="xs-goods-title ss-line-1" mode="aspectFit"
:style="[{ color: titleColor, width: titleWidth ? titleWidth + 'rpx' : '' }]"> ></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 }} {{ data.title || data.name }}
</view> </view>
<!-- 这里是新加的会员价和限时优惠 --> <view
<view class="iconBox" v-if="data.discountPrice || data.vipPrice || data.reward"> v-if="goodsFields.price?.show"
<view class="card" v-if="iconShow">{{iconShow}}</view> class="xs-goods-price font-OPPOSANS"
<view class="card2" v-if="data.reward">{{data.reward.rewardActivity}}</view> :style="[{ color: goodsFields.price.color }]"
</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> <text class="price-unit ss-font-24">{{ priceUnit }}</text>
<text v-if="iconShow=='限时优惠'">{{fen2yuan(data.discountPrice)}}</text> {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
<text v-else-if="iconShow==''">{{fen2yuan(data.vipPrice)}}</text>
<text v-else>{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}</text>
</view> </view>
</view> </view>
</view> </view>
@ -34,26 +43,30 @@
<view v-if="tagStyle.show" class="tag-icon-box"> <view v-if="tagStyle.show" class="tag-icon-box">
<image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image> <image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image>
</view> </view>
<image class="sm-img-box" :src="sheep.$url.cdn(data.image || data.picUrl)" mode="aspectFill"></image> <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" <view
class="sm-goods-content" :style="[{ color: titleColor, width: titleWidth ? titleWidth + 'rpx' : '' }]"> v-if="goodsFields.title?.show || goodsFields.name?.show || goodsFields.price?.show"
<view v-if="goodsFields.title?.show || goodsFields.name?.show" class="sm-goods-content"
class="sm-goods-title ss-line-1 ss-m-b-16"> :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 }} {{ data.title || data.name }}
</view> </view>
<!-- 这里是新加的会员价和限时优惠 --> <view
<view class="iconBox" v-if="data.discountPrice || data.vipPrice || data.reward"> v-if="goodsFields.price?.show"
<view class="card" v-if="iconShow">{{iconShow}}</view> class="sm-goods-price font-OPPOSANS"
<view class="card2" v-if="data.reward">{{data.reward.rewardActivity}}</view> :style="[{ color: goodsFields.price.color }]"
</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> <text class="price-unit ss-font-24">{{ priceUnit }}</text>
<text v-if="iconShow=='限时优惠'">{{fen2yuan(data.discountPrice)}}</text> {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
<text v-else-if="iconShow==''">{{fen2yuan(data.vipPrice)}}</text>
<text v-else>{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}</text>
</view> </view>
</view> </view>
</view> </view>
@ -63,43 +76,58 @@
<view v-if="tagStyle.show" class="tag-icon-box"> <view v-if="tagStyle.show" class="tag-icon-box">
<image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image> <image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image>
</view> </view>
<image class="md-img-box" :src="sheep.$url.cdn(data.image || data.picUrl)" mode="widthFix"></image> <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"> class="md-img-box"
<view v-if="goodsFields.title?.show || goodsFields.name?.show" class="md-goods-title ss-line-1" :src="sheep.$url.cdn(data.image || data.picUrl)"
:style="[{ color: titleColor, width: titleWidth ? titleWidth + 'rpx' : '' }]"> 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 }} {{ data.title || data.name }}
</view> </view>
<view v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show" <view
v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show"
class="md-goods-subtitle ss-m-t-16 ss-line-1" class="md-goods-subtitle ss-m-t-16 ss-line-1"
:style="[{ color: subTitleColor, background: subTitleBackground }]"> :style="[{ color: subTitleColor, background: subTitleBackground }]"
>
{{ data.subtitle || data.introduction }} {{ data.subtitle || data.introduction }}
</view> </view>
<slot name="activity"> <slot name="activity">
<view v-if="data.promos?.length" class="tag-box ss-flex-wrap ss-flex ss-col-center"> <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"> <view
class="activity-tag ss-m-r-10 ss-m-t-16"
v-for="item in data.promos"
:key="item.id"
>
{{ item.title }} {{ item.title }}
</view> </view>
</view> </view>
</slot> </slot>
<!-- 这里是新加的会员价和限时优惠 -->
<view class="iconBox" v-if="data.discountPrice || data.vipPrice || data.reward">
<view class="card" v-if="iconShow">{{iconShow}}</view>
<view class="card2" v-if="data.reward">{{data.reward.rewardActivity}}</view>
</view>
<!-- 这里是新加的会员价和限时优惠结束 -->
<view class="ss-flex ss-col-bottom"> <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" <view
:style="[{ color: goodsFields.price.color }]"> 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> <text class="price-unit ss-font-24">{{ priceUnit }}</text>
<text v-if="iconShow=='限时优惠'">{{fen2yuan(data.discountPrice)}}</text> {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
<text v-else-if="iconShow==''">{{fen2yuan(data.vipPrice)}}</text>
<text v-else>{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}</text>
</view> </view>
<view v-if=" <view
v-if="
(goodsFields.original_price?.show || goodsFields.marketPrice?.show) && (goodsFields.original_price?.show || goodsFields.marketPrice?.show) &&
(data.original_price > 0 || data.marketPrice > 0) (data.original_price > 0 || data.marketPrice > 0)
" class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex" :style="[{ color: originPriceColor }]"> "
class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex"
:style="[{ color: originPriceColor }]"
>
<text class="price-unit ss-font-20">{{ priceUnit }}</text> <text class="price-unit ss-font-20">{{ priceUnit }}</text>
<view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view> <view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view>
</view> </view>
@ -118,7 +146,12 @@
</view> </view>
<!-- lg卡片横向型一行放一个图片左内容右边 --> <!-- lg卡片横向型一行放一个图片左内容右边 -->
<view v-if="size === 'lg'" class="lg-goods-card ss-flex ss-col-stretch" :style="[elStyles]" @tap="onClick"> <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"> <view v-if="tagStyle.show" class="tag-icon-box">
<image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image> <image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image>
</view> </view>
@ -126,16 +159,25 @@
<view v-if="grouponTag" class="groupon-tag ss-flex ss-row-center"> <view v-if="grouponTag" class="groupon-tag ss-flex ss-row-center">
<view class="tag-icon">拼团</view> <view class="tag-icon">拼团</view>
</view> </view>
<image class="lg-img-box" :src="sheep.$url.cdn(data.image || data.picUrl)" mode="aspectFill"></image> <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 class="lg-goods-content ss-flex-1 ss-flex-col ss-row-between ss-p-b-10 ss-p-t-20">
<view> <view>
<view v-if="goodsFields.title?.show || goodsFields.name?.show" class="lg-goods-title ss-line-2" <view
:style="[{ color: titleColor }]"> v-if="goodsFields.title?.show || goodsFields.name?.show"
class="lg-goods-title ss-line-2"
:style="[{ color: titleColor }]"
>
{{ data.title || data.name }} {{ data.title || data.name }}
</view> </view>
<view v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show" <view
v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show"
class="lg-goods-subtitle ss-m-t-10 ss-line-1" class="lg-goods-subtitle ss-m-t-10 ss-line-1"
:style="[{ color: subTitleColor, background: subTitleBackground }]"> :style="[{ color: subTitleColor, background: subTitleBackground }]"
>
{{ data.subtitle || data.introduction }} {{ data.subtitle || data.introduction }}
</view> </view>
</view> </view>
@ -147,27 +189,25 @@
</view> </view>
</view> </view>
</slot> </slot>
<!-- 这里是新加的会员价和限时优惠 -->
<view class="iconBox" v-if="data.discountPrice || data.vipPrice || data.reward">
<view class="card" v-if="iconShow">{{iconShow}}</view>
<view class="card2" v-if="data.reward">{{data.reward.rewardActivity}}</view>
</view>
<!-- 这里是新加的会员价和限时优惠结束 -->
<view class="ss-flex ss-col-bottom ss-m-t-10"> <view class="ss-flex ss-col-bottom ss-m-t-10">
<view v-if="goodsFields.price?.show" <view
v-if="goodsFields.price?.show"
class="lg-goods-price ss-m-r-12 ss-flex ss-col-bottom font-OPPOSANS" class="lg-goods-price ss-m-r-12 ss-flex ss-col-bottom font-OPPOSANS"
:style="[{ color: goodsFields.price.color }]"> :style="[{ color: goodsFields.price.color }]"
>
<text class="ss-font-24">{{ priceUnit }}</text> <text class="ss-font-24">{{ priceUnit }}</text>
{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }} {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
</view> </view>
<view v-if=" <view
v-if="
(goodsFields.original_price?.show || goodsFields.marketPrice?.show) && (goodsFields.original_price?.show || goodsFields.marketPrice?.show) &&
(data.original_price > 0 || data.marketPrice > 0) (data.original_price > 0 || data.marketPrice > 0)
" class="goods-origin-price ss-flex ss-col-bottom font-OPPOSANS" :style="[{ color: originPriceColor }]"> "
class="goods-origin-price ss-flex ss-col-bottom font-OPPOSANS"
:style="[{ color: originPriceColor }]"
>
<text class="price-unit ss-font-20">{{ priceUnit }}</text> <text class="price-unit ss-font-20">{{ priceUnit }}</text>
<text v-if="iconShow=='限时优惠'">{{fen2yuan(data.discountPrice)}}</text> <view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view>
<text v-else-if="iconShow==''">{{fen2yuan(data.vipPrice)}}</text>
<text v-else>{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}</text>
</view> </view>
</view> </view>
<view class="ss-m-t-8 ss-flex ss-col-center ss-flex-wrap"> <view class="ss-m-t-8 ss-flex ss-col-center ss-flex-wrap">
@ -187,45 +227,54 @@
<image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image> <image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image>
</view> </view>
<image class="sl-img-box" :src="sheep.$url.cdn(data.image || data.picUrl)" mode="aspectFill"></image> <image
class="sl-img-box"
:src="sheep.$url.cdn(data.image || data.picUrl)"
mode="aspectFill"
></image>
<view class="sl-goods-content"> <view class="sl-goods-content">
<view> <view>
<view v-if="goodsFields.title?.show || goodsFields.name?.show" class="sl-goods-title ss-line-1" <view
:style="[{ color: titleColor }]"> v-if="goodsFields.title?.show || goodsFields.name?.show"
class="sl-goods-title ss-line-1"
:style="[{ color: titleColor }]"
>
{{ data.title || data.name }} {{ data.title || data.name }}
</view> </view>
<view v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show" <view
v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show"
class="sl-goods-subtitle ss-m-t-16" class="sl-goods-subtitle ss-m-t-16"
:style="[{ color: subTitleColor, background: subTitleBackground }]"> :style="[{ color: subTitleColor, background: subTitleBackground }]"
>
{{ data.subtitle || data.introduction }} {{ data.subtitle || data.introduction }}
</view> </view>
</view> </view>
<view> <view>
<slot name="activity"> <slot name="activity">
<view v-if="data.promos?.length" class="tag-box ss-flex ss-col-center ss-flex-wrap"> <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"> <view
class="activity-tag ss-m-r-10 ss-m-t-16"
v-for="item in data.promos"
:key="item.id"
>
{{ item.title }} {{ item.title }}
</view> </view>
</view> </view>
</slot> </slot>
<!-- 这里是新加的会员价和限时优惠 -->
<view class="iconBox" v-if="data.discountPrice || data.vipPrice || data.reward">
<view class="card" v-if="iconShow">{{iconShow}}</view>
<view class="card2" v-if="data.reward">{{data.reward.rewardActivity}}</view>
</view>
<!-- 这里是新加的会员价和限时优惠结束 -->
<view v-if="goodsFields.price?.show" class="ss-flex ss-col-bottom font-OPPOSANS"> <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 }]"> <view class="sl-goods-price ss-m-r-12" :style="[{ color: goodsFields.price.color }]">
<text class="price-unit ss-font-24">{{ priceUnit }}</text> <text class="price-unit ss-font-24">{{ priceUnit }}</text>
<text v-if="iconShow=='限时优惠'">{{fen2yuan(data.discountPrice)}}</text> {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
<text v-else-if="iconShow==''">{{fen2yuan(data.vipPrice)}}</text>
<text v-else>{{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}</text>
</view> </view>
<view v-if=" <view
v-if="
(goodsFields.original_price?.show || goodsFields.marketPrice?.show) && (goodsFields.original_price?.show || goodsFields.marketPrice?.show) &&
(data.original_price > 0 || data.marketPrice > 0) (data.original_price > 0 || data.marketPrice > 0)
" class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex" :style="[{ color: originPriceColor }]"> "
class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex"
:style="[{ color: originPriceColor }]"
>
<text class="price-unit ss-font-20">{{ priceUnit }}</text> <text class="price-unit ss-font-20">{{ priceUnit }}</text>
<view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view> <view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view>
</view> </view>
@ -272,26 +321,12 @@
* @event {Function()} click - 点击卡片 * @event {Function()} click - 点击卡片
* *
*/ */
import { import { computed, reactive, getCurrentInstance, onMounted, nextTick } from 'vue';
computed,
reactive,
getCurrentInstance,
onMounted,
nextTick,
ref
} from 'vue';
import sheep from '@/sheep'; import sheep from '@/sheep';
import { import { fen2yuan, formatSales } from '@/sheep/hooks/useGoods';
fen2yuan, import { formatStock } from '@/sheep/hooks/useGoods';
formatSales import { isArray } from 'lodash-es';
} from '@/sheep/hooks/useGoods';
import {
formatStock
} from '@/sheep/hooks/useGoods';
import goodsCollectVue from '@/pages/user/goods-collect.vue';
import {
isArray
} from 'lodash-es';
// //
const state = reactive({}); const state = reactive({});
@ -302,39 +337,27 @@
default() { default() {
return { return {
// //
price: { price: { show: true },
show: true
},
// //
stock: { stock: { show: true },
show: true
},
// //
name: { name: { show: true },
show: true
},
// //
introduction: { introduction: { show: true },
show: true
},
// //
marketPrice: { marketPrice: { show: true },
show: true
},
// //
salesCount: { salesCount: { show: true },
show: true
},
}; };
}, },
}, },
tagStyle: { tagStyle: {
type: Object, type: Object,
default: {}, default: () => ({}),
}, },
data: { data: {
type: Object, type: Object,
default: {}, default: () => ({}),
}, },
size: { size: {
type: String, type: String,
@ -393,25 +416,7 @@
default: false, default: false,
}, },
}); });
//
const iconShow = handle()
function handle() {
if (props.data.discountPrice === null && props.data.vipPrice === null) {
// null
return '';
} else if (props.data.discountPrice === null) {
// discountPrice null vipPrice
return '会员价';
} else if (props.data.vipPrice === null) {
// vipPrice null discountPrice
return '限时优惠';
} else if (props.data.discountPrice < props.data.vipPrice) {
return '限时优惠';
} else if (props.data.discountPrice > props.data.vipPrice) {
return '会员价';
}
}
// //
const elStyles = computed(() => { const elStyles = computed(() => {
return { return {
@ -443,18 +448,13 @@
}; };
// //
const { const { proxy } = getCurrentInstance();
proxy
} = getCurrentInstance();
const elId = `sheep_${Math.ceil(Math.random() * 10e5).toString(36)}`; const elId = `sheep_${Math.ceil(Math.random() * 10e5).toString(36)}`;
function getGoodsPriceCardWH() { function getGoodsPriceCardWH() {
if (props.size === 'md') { if (props.size === 'md') {
const view = uni.createSelectorQuery().in(proxy); const view = uni.createSelectorQuery().in(proxy);
view.select(`#${elId}`).fields({ view.select(`#${elId}`).fields({ size: true, scrollOffset: true });
size: true,
scrollOffset: true
});
view.exec((data) => { view.exec((data) => {
let totalHeight = 0; let totalHeight = 0;
const goodsPriceCard = data[0]; const goodsPriceCard = data[0];
@ -469,6 +469,7 @@
}); });
} }
} }
onMounted(() => { onMounted(() => {
nextTick(() => { nextTick(() => {
getGoodsPriceCardWH(); getGoodsPriceCardWH();
@ -762,31 +763,4 @@
color: #ffffff; color: #ffffff;
} }
} }
.card {
width: fit-content;
height: fit-content;
padding: 2rpx 10rpx;
background-color: red;
color: #ffffff;
font-size: 24rpx;
}
.card2 {
width: fit-content;
height: fit-content;
padding: 2rpx 10rpx;
background-color: rgb(255, 242, 241);
color: #ff2621;
font-size: 24rpx;
margin-left: 5rpx;
}
.iconBox {
width: 100%;
height: fit-content;
margin-top: 10rpx;
display: flex;
justify-content: flex-start;
}
</style> </style>

View File

@ -1,83 +1,166 @@
<!-- 装修组件 - 拼团 --> <!-- 装修商品组件拼团商品卡片 -->
<template> <template>
<!-- 商品卡片 -->
<view> <view>
<!-- 布局1. 单列大图上图下内容-->
<view <view
v-if="layoutType === 'threeCol'" v-if="layoutType === LayoutTypeEnum.ONE_COL_BIG_IMG && state.spuList.length"
class="goods-sm-box ss-flex ss-flex-wrap" class="goods-sl-box"
:style="[{ margin: '-' + data.space + 'rpx' }]"
> >
<view <view
v-for="product in productList" class="goods-box"
:key="product.id" v-for="item in state.spuList"
class="goods-card-box" :key="item.id"
:style="[ :style="[{ marginBottom: data.space * 2 + 'rpx' }]"
{
padding: data.space + 'rpx',
},
]"
> >
<s-goods-column <s-goods-column
class="goods-card" class=""
size="sm" size="sl"
:goodsFields="data.fields" :goodsFields="data.fields"
:tagStyle="tagStyle" :tagStyle="data.badge"
:data="product" :data="item"
:titleColor="data.fields.name?.color" :titleColor="data.fields.name?.color"
:subTitleColor="data.fields.introduction.color"
:topRadius="data.borderRadiusTop" :topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom" :bottomRadius="data.borderRadiusBottom"
@click=" @click="sheep.$router.go('/pages/goods/groupon', { id: item.activityId })"
sheep.$router.go('/pages/goods/groupon', { >
id: props.data.activityId, <!-- 购买按钮 -->
}) <template v-slot:cart>
" <button class="ss-reset-button cart-btn" :style="[buyStyle]">
></s-goods-column> {{ btnBuy.type === 'text' ? btnBuy.text : '' }}
</button>
</template>
</s-goods-column>
</view> </view>
</view> </view>
<!-- 样式2 一行一个 图片左 文案右 -->
<view class="goods-box" v-if="layoutType === 'oneCol'"> <!-- 布局2. 单列小图左图右内容 -->
<view <view
class="goods-list" v-if="layoutType === LayoutTypeEnum.ONE_COL_SMALL_IMG && state.spuList.length"
v-for="(product, index) in productList" class="goods-lg-box"
:key="index" >
:style="[{ marginBottom: space + 'px' }]" <view
class="goods-box"
:style="[{ marginBottom: data.space + 'px' }]"
v-for="item in state.spuList"
:key="item.id"
> >
<s-goods-column <s-goods-column
class="goods-card" class="goods-card"
size="lg" size="lg"
:goodsFields="data.fields" :goodsFields="data.fields"
:tagStyle="tagStyle" :data="item"
:data="product" :tagStyle="data.badge"
:titleColor="data.fields.name?.color" :titleColor="data.fields.name?.color"
:subTitleColor="data.fields.introduction?.color" :subTitleColor="data.fields.introduction.color"
:topRadius="data.borderRadiusTop" :topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom" :bottomRadius="data.borderRadiusBottom"
@click=" @tap="sheep.$router.go('/pages/goods/groupon', { id: item.activityId })"
sheep.$router.go('/pages/goods/groupon', {
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>
<!-- 布局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/groupon', { 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/groupon', { 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> </view>
</template> </template>
<script setup> <script setup>
/** /**
* 拼团 * 商品卡片
*/ */
import { computed, onMounted, ref } from 'vue'; import { computed, onMounted, reactive, ref } from 'vue';
import sheep from '@/sheep'; import sheep from '@/sheep';
import SpuApi from "@/sheep/api/product/spu"; import CombinationApi from '@/sheep/api/promotion/combination';
import CombinationApi from "@/sheep/api/promotion/combination"; import SpuApi from '@/sheep/api/product/spu';
// //
const LayoutTypeEnum = {
//
ONE_COL_BIG_IMG: 'oneColBigImg',
//
TWO_COL: 'twoCol',
//
ONE_COL_SMALL_IMG: 'oneColSmallImg',
};
const state = reactive({
spuList: [],
leftSpuList: [],
rightSpuList: [],
});
const props = defineProps({ const props = defineProps({
data: { data: {
type: Object, type: Object,
@ -89,19 +172,19 @@
}, },
}); });
let { layoutType, tagStyle, btnBuy, space } = props.data; const { layoutType, btnBuy, activityIds } = props.data || {};
let { marginLeft, marginRight } = props.styles; const { marginLeft, marginRight } = props.styles || {};
// //
const buyStyle = computed(() => { const buyStyle = computed(() => {
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',
@ -111,21 +194,124 @@
} }
}); });
const productList = ref([]); //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 getCombinationActivityDetailList(ids) {
const { data } = await CombinationApi.getCombinationActivityListByIds(ids);
return data;
}
/**
* 根据商品编号获取商品详情
* @param ids 商品编号列表
* @return {Promise<undefined>} 商品列表
*/
async function getSpuDetail(ids) {
const { data: spu } = await SpuApi.getSpuDetail(ids);
return spu;
}
//
onMounted(async () => { onMounted(async () => {
// todo@owen Yudao //
const { data: activity } = await CombinationApi.getCombinationActivity(props.data.activityId); const activityList = await getCombinationActivityDetailList(activityIds.join(','));
const { data: spu } = await SpuApi.getSpuDetail(activity.spuId) // SPUspuList
productList.value = [spu]; for (const activity of activityList) {
state.spuList.push(await getSpuDetail(activity.spuId));
}
//
activityList.forEach((activity) => {
//
const combinationPrice = activity.combinationPrice || Infinity;
// spu
const spu = state.spuList.find((spu) => activity.spuId === spu.id);
if (spu) {
//
spu.price = Math.min(combinationPrice, spu.price);
// ID
spu.activityId = activity.id;
}
});
//
if (layoutType === LayoutTypeEnum.TWO_COL) {
//
calculateGoodsColumn();
}
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.goods-list { .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; position: relative;
.cart-btn { .cart-btn {
position: absolute; position: absolute;
bottom: 10rpx; bottom: 18rpx;
right: 20rpx; right: 20rpx;
z-index: 11; z-index: 11;
height: 50rpx; height: 50rpx;
@ -136,19 +322,4 @@
color: #fff; 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

@ -70,8 +70,8 @@
default() {}, default() {},
}, },
}); });
const { mode, goodsFields, mpliveIds } = props.data ?? {}; const { mode, goodsFields, mpliveIds } = props.data || {};
const { marginLeft, marginRight } = props.styles ?? {}; const { marginLeft, marginRight } = props.styles || {};
async function getLiveListByIds(ids) { async function getLiveListByIds(ids) {
const { data } = await sheep.$api.app.mplive.getRoomList(ids); const { data } = await sheep.$api.app.mplive.getRoomList(ids);

View File

@ -1,61 +1,31 @@
<!-- 装修基础组件菜单导航金刚区 --> <!-- 装修基础组件菜单导航金刚区 -->
<template> <template>
<!-- 包裹层 --> <!-- 包裹层 -->
<view <view class="ui-swiper" :class="[props.mode, props.ui]"
class="ui-swiper" :style="[bgStyle, { height: swiperHeight + (menuList.length > 1 ? 50 : 0) + 'rpx' }]">
:class="[props.mode, props.bg, props.ui]"
:style="[{ height: swiperHeight + (menuList.length > 1 ? 50 : 0) + 'rpx' }]"
>
<!-- 轮播 --> <!-- 轮播 -->
<swiper <swiper :circular="props.circular" :current="state.cur" :autoplay="props.autoplay" :interval="props.interval"
:circular="props.circular" :duration="props.duration" :style="[{ height: swiperHeight + 'rpx' }]" @change="swiperChange">
:current="state.cur" <swiper-item v-for="(arr, index) in menuList" :key="index" :class="{ cur: state.cur == index }">
:autoplay="props.autoplay"
:interval="props.interval"
:duration="props.duration"
:style="[{ height: swiperHeight + 'rpx' }]"
@change="swiperChange"
>
<swiper-item
v-for="(arr, index) in menuList"
:key="index"
:class="{ cur: state.cur == index }"
>
<!-- 宫格 --> <!-- 宫格 -->
<view class="grid-wrap"> <view class="grid-wrap">
<view <view v-for="(item, index) in arr" :key="index"
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' }]" hover-class="ss-hover-btn"
hover-class="ss-hover-btn" @tap="sheep.$router.go(item.url)">
@tap="sheep.$router.go(item.url)"
>
<view class="menu-box ss-flex ss-flex-col ss-col-center ss-row-center"> <view class="menu-box ss-flex ss-flex-col ss-col-center ss-row-center">
<view <view v-if="item.badge.show" class="tag-box"
v-if="item.badge.show" :style="[{ background: item.badge.bgColor, color: item.badge.textColor }]">
class="tag-box"
:style="[{ background: item.badge.bgColor, color: item.badge.textColor }]"
>
{{ item.badge.text }} {{ item.badge.text }}
</view> </view>
<image <image v-if="item.iconUrl" class="menu-icon" :style="[
v-if="item.iconUrl"
class="menu-icon"
:style="[
{ {
width: props.iconSize + 'rpx', width: props.iconSize + 'rpx',
height: props.iconSize + 'rpx', height: props.iconSize + 'rpx',
}, },
]" ]" :src="sheep.$url.cdn(item.iconUrl)" mode="aspectFill"></image>
:src="sheep.$url.cdn(item.iconUrl)" <view v-if="data.layout === 'iconText'" class="menu-title"
mode="aspectFill" :style="[{ color: item.titleColor }]">
></image>
<view
v-if="data.layout === 'iconText'"
class="menu-title"
:style="[{ color: item.titleColor }]"
>
{{ item.title }} {{ item.title }}
</view> </view>
</view> </view>
@ -66,12 +36,8 @@
<!-- 指示点 --> <!-- 指示点 -->
<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 <view class="line-box" v-for="(item, index) in menuList.length" :key="index"
class="line-box" :class="[state.cur == index ? 'cur' : '', props.dotCur]"></view>
v-for="(item, index) in menuList.length"
:key="index"
:class="[state.cur == index ? 'cur' : '', props.dotCur]"
></view>
</view> </view>
<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="ui-tag radius" :class="[props.dotCur]" style="pointer-events: none"> <view class="ui-tag radius" :class="[props.dotCur]" style="pointer-events: none">
@ -111,7 +77,10 @@
* *
*/ */
import { reactive, computed } from 'vue'; import {
reactive,
computed
} from 'vue';
import sheep from '@/sheep'; import sheep from '@/sheep';
// //
@ -122,13 +91,15 @@
// //
const props = defineProps({ const props = defineProps({
//
data: { data: {
type: Object, type: Object,
default() {}, default: () => ({}),
}, },
//
styles: { styles: {
type: Object, type: Object,
default() {}, default: () => ({}),
}, },
circular: { circular: {
type: Boolean, type: Boolean,
@ -146,7 +117,6 @@
type: Number, type: Number,
default: 500, default: 500,
}, },
ui: { ui: {
type: String, type: String,
default: '', default: '',
@ -164,15 +134,10 @@
type: String, type: String,
default: 'ui-BG-Main', default: 'ui-BG-Main',
}, },
bg: {
type: String,
default: 'bg-none',
},
height: { height: {
type: Number, type: Number,
default: 300, default: 300,
}, },
// //
hasBorder: { hasBorder: {
type: Boolean, type: Boolean,
@ -206,6 +171,21 @@
}, },
}); });
//
const bgStyle = computed(() => {
// props.styles
const {
bgType,
bgImg,
bgColor
} = props.styles;
// bgType
return {
background: bgType === 'img' ? `url(${bgImg}) no-repeat top center / 100% 100%` : bgColor
};
});
// //
const menuList = computed(() => splitData(props.data.list, props.data.row * props.data.column)); const menuList = computed(() => splitData(props.data.list, props.data.row * props.data.column));
const swiperHeight = computed(() => props.data.row * (props.data.layout === 'iconText' ? 200 : 180)); const swiperHeight = computed(() => props.data.row * (props.data.layout === 'iconText' ? 200 : 180));
@ -244,6 +224,7 @@
flex-wrap: wrap; flex-wrap: wrap;
align-items: center; align-items: center;
} }
.menu-box { .menu-box {
position: relative; position: relative;
z-index: 1; z-index: 1;
@ -332,8 +313,7 @@
opacity: 1; opacity: 1;
} }
&.cur::after { &.cur::after {}
}
} }
&.line { &.line {

View File

@ -1,18 +1,12 @@
<!-- 装修基础组件宫格导航 --> <!-- 装修基础组件宫格导航 -->
<template> <template>
<view :style="[bgStyle, { marginLeft: `${data.space}px` }]">
<uni-grid :showBorder="Boolean(data.border)" :column="data.column"> <uni-grid :showBorder="Boolean(data.border)" :column="data.column">
<uni-grid-item <uni-grid-item v-for="(item, index) in data.list" :key="index" @tap="sheep.$router.go(item.url)">
v-for="(item, index) in data.list"
:key="index"
@tap="sheep.$router.go(item.url)"
>
<view class="grid-item-box ss-flex ss-flex-col ss-row-center ss-col-center"> <view class="grid-item-box ss-flex ss-flex-col ss-row-center ss-col-center">
<view class="img-box"> <view class="img-box">
<view <view class="tag-box" v-if="item.badge.show"
class="tag-box" :style="[{ background: item.badge.bgColor, color: item.badge.textColor }]">
v-if="item.badge.show"
:style="[{ background: item.badge.bgColor, color: item.badge.textColor }]"
>
{{ item.badge.text }} {{ item.badge.text }}
</view> </view>
<image class="menu-image" :src="sheep.$url.cdn(item.iconUrl)"></image> <image class="menu-image" :src="sheep.$url.cdn(item.iconUrl)"></image>
@ -29,16 +23,41 @@
</view> </view>
</uni-grid-item> </uni-grid-item>
</uni-grid> </uni-grid>
</view>
</template> </template>
<script setup> <script setup>
import sheep from '@/sheep'; import sheep from '@/sheep';
import {
computed
} from 'vue';
const props = defineProps({ const props = defineProps({
//
data: { data: {
type: Object, type: Object,
default() {}, default: () => ({}),
}, },
//
styles: {
type: Object,
default: () => ({}),
},
});
//
const bgStyle = computed(() => {
// props.styles
const {
bgType,
bgImg,
bgColor
} = props.styles;
// bgType
return {
background: bgType === 'img' ? `url(${bgImg}) no-repeat top center / 100% 100%` : bgColor
};
}); });
</script> </script>
@ -47,6 +66,7 @@
width: 24px; width: 24px;
height: 24px; height: 24px;
} }
.grid-item-box { .grid-item-box {
flex: 1; flex: 1;
display: flex; display: flex;
@ -54,8 +74,10 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
height: 100%; height: 100%;
.img-box { .img-box {
position: relative; position: relative;
.tag-box { .tag-box {
position: absolute; position: absolute;
z-index: 2; z-index: 2;

View File

@ -1,6 +1,6 @@
<!-- 装修用户组件用户订单 --> <!-- 装修用户组件用户订单 -->
<template> <template>
<view class="ss-order-menu-wrap ss-flex ss-col-center"> <view class="ss-order-menu-wrap ss-flex ss-col-center" :style="[style, { marginLeft: `${data.space}px` }]">
<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"
v-for="item in orderMap" v-for="item in orderMap"
@ -67,8 +67,32 @@
path: '/pages/order/list', path: '/pages/order/list',
}, },
]; ];
//
const props = defineProps({
//
data: {
type: Object,
default: () => ({}),
},
//
styles: {
type: Object,
default: () => ({}),
},
});
//
const numData = computed(() => sheep.$store('user').numData); const numData = computed(() => sheep.$store('user').numData);
//
const style = computed(() => {
// props.styles
const { bgType, bgImg, bgColor } = props.styles;
// bgType
return {
background: bgType === 'img'
? `url(${bgImg}) no-repeat top center / 100% 100%`
: bgColor
};
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -1,86 +1,166 @@
<!-- 装修组件 - 秒杀 --> <!-- 装修商品组件秒杀商品卡片 -->
<template> <template>
<!-- 商品卡片 -->
<view> <view>
<!-- 样式一三列 - 上图下文 --> <!-- 布局1. 单列大图上图下内容-->
<view <view
v-if="layoutType === 'threeCol'" v-if="layoutType === LayoutTypeEnum.ONE_COL_BIG_IMG && state.spuList.length"
class="goods-sm-box ss-flex ss-flex-wrap" class="goods-sl-box"
:style="[{ margin: '-' + data.space + 'rpx' }]"
> >
<view <view
v-for="product in productList" class="goods-box"
:key="product.id" v-for="item in state.spuList"
class="goods-card-box" :key="item.id"
:style="[ :style="[{ marginBottom: data.space * 2 + 'rpx' }]"
{
padding: data.space + 'rpx',
},
]"
> >
<s-goods-column <s-goods-column
class="goods-card" class=""
size="sm" size="sl"
:goodsFields="data.fields" :goodsFields="data.fields"
:tagStyle="tagStyle" :tagStyle="data.badge"
:data="product" :data="item"
:titleColor="data.fields.name?.color" :titleColor="data.fields.name?.color"
:subTitleColor="data.fields.introduction.color"
:topRadius="data.borderRadiusTop" :topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom" :bottomRadius="data.borderRadiusBottom"
@click=" @click="sheep.$router.go('/pages/goods/seckill', { id: item.activityId })"
sheep.$router.go('/pages/goods/seckill', { >
id: props.data.activityId, <!-- 购买按钮 -->
}) <template v-slot:cart>
" <button class="ss-reset-button cart-btn" :style="[buyStyle]">
></s-goods-column> {{ btnBuy.type === 'text' ? btnBuy.text : '' }}
</button>
</template>
</s-goods-column>
</view> </view>
</view> </view>
<!-- 样式二一列 - 左图右文 -->
<view class="goods-box" v-if="layoutType === 'oneCol'"> <!-- 布局2. 单列小图左图右内容 -->
<view <view
class="goods-list" v-if="layoutType === LayoutTypeEnum.ONE_COL_SMALL_IMG && state.spuList.length"
v-for="(product, index) in productList" class="goods-lg-box"
:key="index" >
:style="[{ marginBottom: space + 'px' }]" <view
class="goods-box"
:style="[{ marginBottom: data.space + 'px' }]"
v-for="item in state.spuList"
:key="item.id"
> >
<s-goods-column <s-goods-column
class="goods-card" class="goods-card"
size="lg" size="lg"
:goodsFields="data.fields" :goodsFields="data.fields"
:tagStyle="tagStyle" :data="item"
:data="product" :tagStyle="data.badge"
:titleColor="data.fields.name?.color" :titleColor="data.fields.name?.color"
:subTitleColor="data.fields.introduction?.color" :subTitleColor="data.fields.introduction.color"
:topRadius="data.borderRadiusTop" :topRadius="data.borderRadiusTop"
:bottomRadius="data.borderRadiusBottom" :bottomRadius="data.borderRadiusBottom"
@click=" @tap="sheep.$router.go('/pages/goods/seckill', { id: item.activityId })"
sheep.$router.go('/pages/goods/seckill', {
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>
<!-- 布局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/seckill', { 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/seckill', { 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> </view>
</template> </template>
<script setup> <script setup>
/** /**
* 秒杀商品列表 * 商品卡片
*
* @property {Array} list 商品列表
*/ */
import { computed, onMounted, ref } from 'vue'; import { computed, onMounted, reactive, ref } from 'vue';
import sheep from '@/sheep'; import sheep from '@/sheep';
import SeckillApi from "@/sheep/api/promotion/seckill"; import SeckillApi from '@/sheep/api/promotion/seckill';
import SpuApi from "@/sheep/api/product/spu"; import SpuApi from '@/sheep/api/product/spu';
// //
const LayoutTypeEnum = {
//
ONE_COL_BIG_IMG: 'oneColBigImg',
//
TWO_COL: 'twoCol',
//
ONE_COL_SMALL_IMG: 'oneColSmallImg',
};
const state = reactive({
spuList: [],
leftSpuList: [],
rightSpuList: [],
});
const props = defineProps({ const props = defineProps({
data: { data: {
type: Object, type: Object,
@ -92,18 +172,19 @@
}, },
}); });
let { layoutType, tagStyle, btnBuy, space } = props.data; const { layoutType, btnBuy, activityIds } = props.data || {};
let { marginLeft, marginRight } = props.styles; const { marginLeft, marginRight } = props.styles || {};
// //
const buyStyle = computed(() => { const buyStyle = computed(() => {
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',
@ -113,30 +194,124 @@
} }
}); });
// //region
const productList = ref([]); //
// 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 getSeckillActivityDetailList(ids) {
const { data } = await SeckillApi.getSeckillActivityListByIds(ids);
return data;
}
/**
* 根据商品编号获取商品详情
* @param ids 商品编号列表
* @return {Promise<undefined>} 商品列表
*/
async function getSpuDetail(ids) {
const { data: spu } = await SpuApi.getSpuDetail(ids);
return spu;
}
//
onMounted(async () => { onMounted(async () => {
// todo@owen Yudao //
const { data: activity } = await SeckillApi.getSeckillActivity(props.data.activityId); const activityList = await getSeckillActivityDetailList(activityIds.join(','));
const { data: spu } = await SpuApi.getSpuDetail(activity.spuId) // SPUspuList
productList.value = [spu]; for (const activity of activityList) {
state.spuList.push(await getSpuDetail(activity.spuId));
}
//
activityList.forEach((activity) => {
//
const seckillPrice = activity.seckillPrice || Infinity;
// spu
const spu = state.spuList.find((spu) => activity.spuId === spu.id);
if (spu) {
//
spu.price = Math.min(seckillPrice, spu.price);
// ID
spu.activityId = activity.id;
}
});
//
if (layoutType === LayoutTypeEnum.TWO_COL) {
//
calculateGoodsColumn();
}
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.header-box { .goods-md-wrap {
height: 100rpx; width: 100%;
} }
.goods-list { .goods-list-box {
position: relative; width: 50%;
box-sizing: border-box;
.left-list {
&:nth-last-child(1) { &:nth-last-child(1) {
margin-bottom: 0 !important; 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 { .cart-btn {
position: absolute; position: absolute;
bottom: 10rpx; bottom: 18rpx;
right: 20rpx; right: 20rpx;
z-index: 11; z-index: 11;
height: 50rpx; height: 50rpx;
@ -147,14 +322,4 @@
color: #fff; 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>

View File

@ -5,7 +5,11 @@
<view class="ss-modal-box bg-white ss-flex-col"> <view class="ss-modal-box bg-white ss-flex-col">
<view class="modal-header ss-flex ss-col-center"> <view class="modal-header ss-flex ss-col-center">
<view class="header-left ss-m-r-30"> <view class="header-left ss-m-r-30">
<image class="sku-image" :src="sheep.$url.cdn(state.selectedSku.picUrl || goodsInfo.picUrl)" mode="aspectFill" /> <image
class="sku-image"
:src="sheep.$url.cdn(state.selectedSku.picUrl || goodsInfo.picUrl)"
mode="aspectFill"
/>
</view> </view>
<view class="header-right ss-flex-col ss-row-between ss-flex-1"> <view class="header-right ss-flex-col ss-row-between ss-flex-1">
<view class="goods-title ss-line-2"> <view class="goods-title ss-line-2">
@ -22,7 +26,13 @@
</view> </view>
</view> </view>
<view class="header-right-bottom ss-flex ss-col-center ss-row-between"> <view class="header-right-bottom ss-flex ss-col-center ss-row-between">
<view class="price-text"> {{ fen2yuan(goodsInfo.price) }}</view> <view class="price-text">
{{
fen2yuan(
state.selectedSku.price || goodsInfo.price || state.selectedSku.marketPrice,
)
}}</view
>
<view class="stock-text ss-m-l-20"> <view class="stock-text ss-m-l-20">
库存{{ state.selectedSku.stock || goodsInfo.stock }} 库存{{ state.selectedSku.stock || goodsInfo.stock }}
@ -35,22 +45,35 @@
<view class="sku-item ss-m-b-20" v-for="property in propertyList" :key="property.id"> <view class="sku-item ss-m-b-20" v-for="property in propertyList" :key="property.id">
<view class="label-text ss-m-b-20">{{ property.name }}</view> <view class="label-text ss-m-b-20">{{ property.name }}</view>
<view class="ss-flex ss-col-center ss-flex-wrap"> <view class="ss-flex ss-col-center ss-flex-wrap">
<button class="ss-reset-button spec-btn" v-for="value in property.values" :class="[ <button
class="ss-reset-button spec-btn"
v-for="value in property.values"
:class="[
{ {
'checked-btn': state.currentPropertyArray[property.id] === value.id, 'checked-btn': state.currentPropertyArray[property.id] === value.id,
}, },
{ {
'disabled-btn': value.disabled === true, 'disabled-btn': value.disabled === true,
}, },
]" :key="value.id" :disabled="value.disabled === true" @tap="onSelectSku(property.id, value.id)"> ]"
:key="value.id"
:disabled="value.disabled === true"
@tap="onSelectSku(property.id, value.id)"
>
{{ value.name }} {{ value.name }}
</button> </button>
</view> </view>
</view> </view>
<view class="buy-num-box ss-flex ss-col-center ss-row-between"> <view class="buy-num-box ss-flex ss-col-center ss-row-between">
<view class="label-text">购买数量</view> <view class="label-text">购买数量</view>
<su-number-box :min="1" :max="state.selectedSku.stock" :step="1" <su-number-box
v-model="state.selectedSku.count" @change="onNumberChange($event)" activity="groupon" /> :min="1"
:max="state.selectedSku.stock"
:step="1"
v-model="state.selectedSku.count"
@change="onNumberChange($event)"
activity="groupon"
/>
</view> </view>
</scroll-view> </scroll-view>
</view> </view>
@ -63,7 +86,16 @@
<view class="btn-title">{{ grouponNum + '人团' }}</view> <view class="btn-title">{{ grouponNum + '人团' }}</view>
</button> </button>
<button class="ss-reset-button btn-tox ss-flex-col" @tap="onBuy"> <button class="ss-reset-button btn-tox ss-flex-col" @tap="onBuy">
<view class="btn-price">{{ fen2yuan(goodsInfo.price) }}</view> <view class="btn-price">
{{
fen2yuan(
state.selectedSku.price * state.selectedSku.count ||
goodsInfo.price * state.selectedSku.count ||
state.selectedSku.marketPrice * state.selectedSku.count ||
goodsInfo.price,
)
}}
</view>
<view v-if="grouponAction === 'create'"></view> <view v-if="grouponAction === 'create'"></view>
<view v-else-if="grouponAction === 'join'">参与拼团</view> <view v-else-if="grouponAction === 'join'">参与拼团</view>
</button> </button>
@ -111,7 +143,7 @@
const skuList = computed(() => { const skuList = computed(() => {
let skuPrices = props.goodsInfo.skus; let skuPrices = props.goodsInfo.skus;
for (let price of skuPrices) { for (let price of skuPrices) {
price.value_id_array = price.properties.map((item) => item.valueId) price.value_id_array = price.properties.map((item) => item.valueId);
} }
return skuPrices; return skuPrices;
}); });
@ -120,7 +152,8 @@
() => state.selectedSku, () => state.selectedSku,
(newVal) => { (newVal) => {
emits('change', newVal); emits('change', newVal);
}, { },
{
immediate: true, // immediate: true, //
deep: true, // deep: true, //
}, },
@ -245,7 +278,10 @@
function onSelectSku(propertyId, valueId) { function onSelectSku(propertyId, valueId) {
// //
let isChecked = true; // or let isChecked = true; // or
if (state.currentPropertyArray[propertyId] !== undefined && state.currentPropertyArray[propertyId] === valueId) { if (
state.currentPropertyArray[propertyId] !== undefined &&
state.currentPropertyArray[propertyId] === valueId
) {
// '' // ''
isChecked = false; isChecked = false;
state.currentPropertyArray.splice(propertyId, 1, ''); state.currentPropertyArray.splice(propertyId, 1, '');

View File

@ -5,7 +5,7 @@
<!-- SKU 信息 --> <!-- SKU 信息 -->
<view class="ss-modal-box bg-white ss-flex-col"> <view class="ss-modal-box bg-white ss-flex-col">
<view class="modal-header ss-flex ss-col-center"> <view class="modal-header ss-flex ss-col-center">
<!-- 规格图 --> <!-- 规格图 -->
<view class="header-left ss-m-r-30"> <view class="header-left ss-m-r-30">
<image <image
class="sku-image" class="sku-image"
@ -125,10 +125,6 @@
return skuPrices; return skuPrices;
}); });
if (!state.goodsInfo.is_sku) {
state.selectedSku = state.goodsInfo.skus[0];
}
watch( watch(
() => state.selectedSku, () => state.selectedSku,
(newVal) => { (newVal) => {

View File

@ -66,7 +66,7 @@
css: { css: {
// //
width: sheep.$platform.device.windowWidth * 0.9, width: sheep.$platform.device.windowWidth * 0.9,
height: 550, height: 600,
}, },
views: [], views: [],
}); });

View File

@ -82,12 +82,12 @@ const groupon = async (poster) => {
type: 'text', type: 'text',
text: '2人团', text: '2人团',
css: { css: {
color: '#ff0000', color: '#fff',
fontSize: 30, fontSize: 12,
fontFamily: 'OPPOSANS', fontFamily: 'OPPOSANS',
position: 'fixed', position: 'fixed',
left: width * 0.3, left: width * 0.84,
top: width * 1.32, top: width * 1.3,
}, },
}, },
// #ifndef MP-WEIXIN // #ifndef MP-WEIXIN
@ -96,7 +96,7 @@ const groupon = async (poster) => {
text: poster.shareInfo.link, text: poster.shareInfo.link,
css: { css: {
position: 'fixed', position: 'fixed',
left: width * 0.75, left: width * 0.5,
top: width * 1.3, top: width * 1.3,
width: width * 0.2, width: width * 0.2,
height: width * 0.2, height: width * 0.2,

View File

@ -1,10 +1,6 @@
<!-- 装修商品组件标题栏 --> <!-- 装修商品组件标题栏 -->
<template> <template>
<view <view class="ss-title-wrap ss-flex ss-col-center" :class="[state.typeMap[data.textAlign]]" :style="[bgStyle, { marginLeft: `${data.space}px` }]">
class="ss-title-wrap ss-flex ss-col-center"
:class="[state.typeMap[data.textAlign]]"
:style="[elStyles]"
>
<view class="title-content"> <view class="title-content">
<!-- 主标题 --> <!-- 主标题 -->
<view v-if="data.title" class="title-text" :style="[titleStyles]">{{ data.title }}</view> <view v-if="data.title" class="title-text" :style="[titleStyles]">{{ data.title }}</view>
@ -24,7 +20,10 @@
/** /**
* 标题栏 * 标题栏
*/ */
import { reactive } from 'vue'; import {
reactive,
computed
} from 'vue';
import sheep from '@/sheep'; import sheep from '@/sheep';
// //
@ -37,22 +36,31 @@
// //
const props = defineProps({ const props = defineProps({
//
data: { data: {
type: Object, type: Object,
default() {}, default: () => ({}),
}, },
//
styles: { styles: {
type: Object, type: Object,
default() {}, default: () => ({}),
}, },
}); });
//
const bgStyle = computed(() => {
// props.styles
const {
bgType,
bgImg,
bgColor
} = props.styles;
// // bgType
const elStyles = { return {
background: `url(${sheep.$url.cdn(props.data.bgImgUrl)}) no-repeat top center / 100% auto`, background: bgType === 'img' ? `url(${bgImg}) no-repeat top center / 100% 100%` : bgColor
fontSize: `${props.data.titleSize}px`,
fontWeight: `${props.data.titleWeight}px`,
}; };
});
// //
const titleStyles = { const titleStyles = {

View File

@ -1,14 +1,15 @@
<!-- 装修用户组件用户卡片 --> <!-- 装修用户组件用户卡片 -->
<template> <template>
<view class="ss-user-info-wrap ss-p-t-50"> <view class="ss-user-info-wrap ss-p-t-50" :style="[bgStyle, { marginLeft: `${data.space}px` }]">
<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 class="avatar-img" :src=" <image class="avatar-img" :src="
isLogin isLogin
? sheep.$url.cdn(userInfo.avatar) ? sheep.$url.cdn(userInfo.avatar)
: sheep.$url.static('/static/img/shop/default_avatar.png') : sheep.$url.static('/static/img/shop/default_avatar.png')"
" mode="aspectFill" @tap="sheep.$router.go('/pages/user/info')"></image> mode="aspectFill" @tap="sheep.$router.go('/pages/user/info')">
</image>
</view> </view>
<view> <view>
<view class="nickname-box ss-flex ss-col-center"> <view class="nickname-box ss-flex ss-col-center">
@ -52,27 +53,30 @@
* *
* *
*/ */
import { import { computed } from 'vue';
computed,
reactive
} from 'vue';
import sheep from '@/sheep'; import sheep from '@/sheep';
import { import {
showShareModal, showShareModal,
showAuthModal showAuthModal,
} from '@/sheep/hooks/useModal'; } 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: { //
type: String, data: {
default: '', type: Object,
default: () => ({}),
},
//
styles: {
type: Object,
default: () => ({}),
}, },
// //
avatar: { avatar: {
@ -97,6 +101,20 @@
}, },
}); });
//
const bgStyle = computed(() => {
// props.styles
const { bgType, bgImg, bgColor } = props.styles;
// bgType
return {
background: bgType === 'img'
? `url(${bgImg}) no-repeat top center / 100% 100%`
: bgColor,
};
});
//
function onBind() { function onBind() {
showAuthModal('changeMobile'); showAuthModal('changeMobile');
} }

View File

@ -1,6 +1,6 @@
<!-- 装修用户组件用户资产 --> <!-- 装修用户组件用户资产 -->
<template> <template>
<view class="ss-wallet-menu-wrap ss-flex ss-col-center"> <view class="ss-wallet-menu-wrap ss-flex ss-col-center" :style="[bgStyle, { marginLeft: `${data.space}px` }]">
<view class="menu-item ss-flex-1 ss-flex-col ss-row-center ss-col-center" <view class="menu-item ss-flex-1 ss-flex-col ss-row-center ss-col-center"
@tap="sheep.$router.go('/pages/user/wallet/money')"> @tap="sheep.$router.go('/pages/user/wallet/money')">
<view class="value-box ss-flex ss-col-bottom"> <view class="value-box ss-flex ss-col-bottom">
@ -44,6 +44,32 @@
import sheep from '@/sheep'; import sheep from '@/sheep';
import { fen2yuan } from '../../hooks/useGoods'; import { fen2yuan } from '../../hooks/useGoods';
//
const props = defineProps({
//
data: {
type: Object,
default: () => ({}),
},
//
styles: {
type: Object,
default: () => ({}),
},
});
//
const bgStyle = computed(() => {
// props.styles
const { bgType, bgImg, bgColor } = props.styles;
// bgType
return {
background: bgType === 'img'
? `url(${bgImg}) no-repeat top center / 100% 100%`
: bgColor
};
});
const userWallet = computed(() => sheep.$store('user').userWallet); const userWallet = computed(() => sheep.$store('user').userWallet);
const userInfo = computed(() => sheep.$store('user').userInfo); const userInfo = computed(() => sheep.$store('user').userInfo);
const numData = computed(() => sheep.$store('user').numData); const numData = computed(() => sheep.$store('user').numData);

View File

@ -621,7 +621,7 @@ function setProperty(obj, key, value) {
function page() { function page() {
const pages = getCurrentPages(); const pages = getCurrentPages();
// 某些特殊情况下(比如页面进行redirectTo时的一些时机)pages可能为空数组 // 某些特殊情况下(比如页面进行redirectTo时的一些时机)pages可能为空数组
return `/${pages[pages.length - 1]?.route ?? ''}`; return `/${pages[pages.length - 1]?.route || ''}`;
} }
/** /**

View File

@ -23,6 +23,10 @@ export function isString(value) {
} }
export function isEmpty(value) { export function isEmpty(value) {
if (value === '' || value === undefined || value === null){
return true;
}
if (isArray(value)) { if (isArray(value)) {
return value.length === 0; return value.length === 0;
} }
@ -31,7 +35,7 @@ export function isEmpty(value) {
return Object.keys(value).length === 0; return Object.keys(value).length === 0;
} }
return value === '' || value === undefined || value === null; return false
} }
export function isBoolean(value) { export function isBoolean(value) {

View File

@ -14,7 +14,7 @@ export function showAuthModal(type = 'smsLogin') {
modal.$patch((state) => { modal.$patch((state) => {
state.auth = type; state.auth = type;
}); });
}, 200); }, 500);
closeAuthModal(); closeAuthModal();
} else { } else {
modal.$patch((state) => { modal.$patch((state) => {

View File

@ -1,9 +1,10 @@
/** /**
* 本模块封装微信浏览器下的一些方法 * 本模块封装微信浏览器下的一些方法
* 更多微信网页开发sdk方法,详见:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html * 更多微信网页开发sdk方法,详见:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html
* the permission value is offline verifying 报错请参考 @see https://segmentfault.com/a/1190000042289419 解决
*/ */
import jweixin, { ready } from 'weixin-js-sdk'; import jweixin from 'weixin-js-sdk';
import $helper from '@/sheep/helper'; import $helper from '@/sheep/helper';
import AuthUtil from '@/sheep/api/member/auth'; import AuthUtil from '@/sheep/api/member/auth';
@ -38,7 +39,7 @@ export default {
timestamp: data.timestamp, timestamp: data.timestamp,
nonceStr: data.nonceStr, nonceStr: data.nonceStr,
signature: data.signature, signature: data.signature,
jsApiList: ['chooseWXPay'], // TODO 芋艿:后续可以设置更多权限; jsApiList: ['chooseWXPay', 'openLocation', 'getLocation','updateTimelineShareData','scanQRCode'], // TODO 芋艿:后续可以设置更多权限;
openTagList: data.openTagList openTagList: data.openTagList
}); });
} }
@ -77,7 +78,7 @@ export default {
}); });
}, },
//获取微信收货地址 TODO 芋艿:未测试 // 获取微信收货地址
openAddress(callback) { openAddress(callback) {
this.isReady(() => { this.isReady(() => {
jweixin.openAddress({ jweixin.openAddress({
@ -137,9 +138,10 @@ export default {
openLocation(data, callback) { openLocation(data, callback) {
this.isReady(() => { this.isReady(() => {
jweixin.openLocation({ jweixin.openLocation({
//根据传入的坐标打开地图 ...data,
latitude: data.latitude, success: function (res) {
longitude: data.longitude, console.log(res);
}
}); });
}); });
}, },

View File

@ -53,7 +53,6 @@ const mobileLogin = async (e) => {
} else { } else {
return resolve(false); return resolve(false);
} }
// TODO 芋艿shareInfo: uni.getStorageSync('shareLog') || {},
}); });
}; };

View File

@ -24,7 +24,6 @@ async function login(code = '', state = '') {
// 解密 code 发起登陆 // 解密 code 发起登陆
const loginResult = await AuthUtil.socialLogin(socialType, code, state); const loginResult = await AuthUtil.socialLogin(socialType, code, state);
if (loginResult.code === 0) { if (loginResult.code === 0) {
// TODO 芋艿shareLog
setOpenid(loginResult.data.openid); setOpenid(loginResult.data.openid);
return loginResult; return loginResult;
} }
@ -103,5 +102,5 @@ export default {
unbind, unbind,
getInfo, getInfo,
getOpenid, getOpenid,
jssdk: $wxsdk, jsWxSdk: $wxsdk,
}; };

View File

@ -186,7 +186,8 @@ const bindBrokerageUser = async (val= undefined) => {
} }
await BrokerageApi.bindBrokerageUser({ bindUserId: shareId }); await BrokerageApi.bindBrokerageUser({ bindUserId: shareId });
uni.removeStorageSync('shareId'); uni.removeStorageSync('shareId');
} catch { } catch (e) {
console.error(e);
} }
}; };

View File

@ -9,7 +9,7 @@ import $store from '@/sheep/store';
import $platform from '@/sheep/platform'; import $platform from '@/sheep/platform';
import { showAuthModal } from '@/sheep/hooks/useModal'; import { showAuthModal } from '@/sheep/hooks/useModal';
import AuthUtil from '@/sheep/api/member/auth'; import AuthUtil from '@/sheep/api/member/auth';
import { getTerminalEnumByUniPlatform } from '@/sheep/util/const'; import { getTerminal } from '@/sheep/util/const';
const options = { const options = {
// 显示操作成功消息 默认不显示 // 显示操作成功消息 默认不显示
@ -94,9 +94,7 @@ http.interceptors.request.use(
if (token) { if (token) {
config.header['Authorization'] = token; config.header['Authorization'] = token;
} }
config.header['terminal'] = getTerminal();
const terminalType = uni.getSystemInfoSync().uniPlatform
config.header['terminal'] = getTerminalEnumByUniPlatform(terminalType);
config.header['Accept'] = '*/*'; config.header['Accept'] = '*/*';
config.header['tenant-id'] = tenantId; config.header['tenant-id'] = tenantId;

View File

@ -57,7 +57,13 @@ const cart = defineStore({
// 移除购物车 // 移除购物车
async delete(ids) { async delete(ids) {
const { code } = await CartApi.deleteCart(ids.join(',')); let idsTemp = '';
if (Array.isArray(ids)) {
idsTemp = ids.join(',');
} else {
idsTemp = ids;
}
const { code } = await CartApi.deleteCart(idsTemp);
if (code === 0) { if (code === 0) {
await this.getList(); await this.getList();
} }

View File

@ -12,26 +12,23 @@ export const TerminalEnum = {
}; };
/** /**
* 将Uniapp提供的平台转换为后端所需的Terminal值 * uni-app 提供的平台转换为后端所需的 terminal值
* @param platformType Uniapp提供的平台类型 *
* @return 终端
*/ */
export const getTerminalEnumByUniPlatform = (platformType) => { export const getTerminal = () => {
let terminal; const platformType = uni.getSystemInfoSync().uniPlatform;
// 与后端terminal枚举一一对应 // 与后端terminal枚举一一对应
switch (platformType) { switch (platformType) {
case 'app': case 'app':
terminal = TerminalEnum.APP; return TerminalEnum.APP;
break;
case 'web': case 'web':
terminal = TerminalEnum.H5; return TerminalEnum.H5;
break;
case 'mp-weixin': case 'mp-weixin':
terminal = TerminalEnum.WECHAT_MINI_PROGRAM; return TerminalEnum.WECHAT_MINI_PROGRAM;
break;
default: default:
terminal = TerminalEnum.UNKNOWN; return TerminalEnum.UNKNOWN;
} }
return terminal;
}; };
// ========== MALL - 营销模块 ========== // ========== MALL - 营销模块 ==========

BIN
static/images/line.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
static/images/writeOff.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB