alipay-emulator/pages/shopping/pdd/list-index.vue

887 lines
23 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="page-container flex-column">
<view class="nav-bar">
<nav-bar v-if="!selectedImage" :buttonGroup="buttonGroup" @button-click="util.clickTitlePopupButton"
tipLayerType="pdd-shopping-list" isTipLayer tipLayerText="添加订单信息">
<!-- 使用作用域插槽自定义按钮渲染特别是switch的checked绑定 -->
<template #button="{ button }">
<view class="button flex-align-center flex-justify-center">
{{ button.name }}
<view @tap.stop>
<switch v-if="button.isSwitch" :checked="couponInfo[button.key]" @change="button.click"
style="transform: scale(0.7);"></switch>
</view>
</view>
</template>
<template v-slot:left>
<image style="width: 48rpx;height: 48rpx;" src="/static/image/shopping/pdd/back.png"
@click="util.goBack()">
</image>
</template>
<template v-slot:center>
<view class="title-box flex-center flex-column">
<view class="title">我的订单</view>
<view class="flex-center text">
<image style="width: 30rpx;height: 30rpx;" src="/static/image/shopping/pdd/safety.png">
</image>
<text>专属客服 ·闪电退换 ·售后无忧</text>
</view>
</view>
</template>
<template v-slot:right>
<image style="width: 48rpx;height: 48rpx;" src="/static/image/shopping/pdd/search.png"></image>
</template>
</nav-bar>
<nav-bar v-else title="拼图" bgColor="#EFEFEF" noBack @back="closeImage" isRightButton
@right-click="confirmImage">
</nav-bar>
</view>
<view class="tab-list flex-align-center">
<view class="tab-item" :class="{ active: tab.id == activeTab }" v-for="(tab, index) in tabList" :key="index"
@click="activeTab = tab.id">
<text>{{ tab.name }}</text>
</view>
</view>
<scroll-view v-if="activeTab === 4" class="tab2-box" scroll-x="true" :show-scrollbar="false">
<view class="tab2-content flex-align-center">
<view class="tab2-item flex-center" :class="{ active: activeTab2 === item.id }"
v-for="(item, index) in displayTab2List" :key="index" @click="handleTab2Click(item)">
<text>{{ item.name }} {{ item.count }}</text>
</view>
</view>
</scroll-view>
<scroll-view class="flex-1" style="height: 100px;" scroll-y="true" :scroll-into-view="scrollIntoId"
scroll-with-animation>
<view v-if="couponInfo.show618Coupon" class="flex-align-center coupon-banner">
<image style="width: 32rpx;height: 28rpx;margin-right: 10rpx;"
src="/static/image/shopping/pdd/coupon-logo.png">
</image>
<view class="flex-align-center flex-1">
<text class="red">618</text>
<text>降价正式开始!再送</text>
<text class="red">{{ couponInfo.coupon618Amount || '188' }}元</text>
<text>优惠券</text>
</view>
<uni-icons type="right" size="14" color="#B7B7B7"></uni-icons>
</view>
<image v-if="couponInfo.hasCoupon" style="width: 100%;height: 300rpx;"
:src="couponInfo.couponPath || '/static/image/shopping/pdd/coupon1.png'" mode="widthFix"></image>
<list-card v-for="(item, index) in filteredOrderList" :key="index" :item="item"
@longpress="handleLongPress($event, item)"></list-card>
<view v-if="filteredOrderList.length == 0" class="null-data-box flex-align-center">
<text>没找到订单?试试</text>
<text style="color: #2686E4;">查看全部</text>
<text>或</text>
<text style="color: #2686E4;">切换账号</text>
</view>
<view class="bottom-fixed" style="height: 1000rpx;">
<view v-if="!selectedImage" class="upload-screenshot-box" @touchstart="handleTouchStart"
@touchend="handleTouchEnd">
<view v-if="!screenshotImage" class="upload-screenshot-content">
<image class="upload-screenshot" src="/static/image/common/upload-screenshot.png"
mode="aspectFit">
</image>
<view class="upload-screenshot-text">长按替换截图</view>
</view>
<view v-else class="screenshot-preview-box">
<image class="screenshot-preview" :src="screenshotImage" mode="widthFix"></image>
</view>
<!-- <image v-else class="w100 h100" :src="screenshotImage" mode="widthFix"></image> -->
</view>
<view v-else class="upload-screenshot-box scroll-image-box">
<scroll-view class="image-box" style="width: 100%;height: 100%;" scroll-y :show-scrollbar="false"
@scroll="onImageScroll">
<image class="crop-image-target" style="width:100%;" :src="selectedImage" mode="widthFix">
</image>
</scroll-view>
<view class="dashed-line-box">
<view class="dashed-line-text">我是分割线</view>
</view>
</view>
<canvas canvas-id="crop-canvas"
style="position: fixed; left: -9999px; width: 750rpx; height: 100vh; pointer-events: none;"></canvas>
<view id="bottom-anchor" style="height: 1px;"></view>
</view>
</scroll-view>
<!-- 上下文菜单和遮罩 -->
<view class="menu-mask" v-if="showMenu" @click="showMenu = false"></view>
<view class="context-menu flex-column" v-if="showMenu" :style="{ left: menuX + 'px', top: menuY + 'px' }">
<view class="menu-item" @click="handleEdit">编辑</view>
<view class="menu-item text-red" @click="handleDelete">删除</view>
</view>
<!-- 水印 -->
<view v-if="$isVip()">
<watermark dark="light" source="uni_alipay_shopping_pdd" />
<liu-drag-button :canDocking="false" @clickBtn="$goRechargePage('watermark', 'uni_alipay_shopping_pdd')">
<c-lottie ref="cLottieRef" :src='$watermark()' width="94px" height='74px' :loop="true"></c-lottie>
</liu-drag-button>
</view>
<!-- 优惠券弹窗 -->
<uni-popup ref="couponPopup" type="center">
<view class="popup-content"
style="width: 620rpx; background-color: #fff; border-radius: 24rpx; padding: 40rpx 30rpx; box-sizing: border-box;">
<view class="flex-align-center flex-between" style="margin-bottom: 30rpx;">
<text style="font-size: 34rpx; font-weight: 500; color: #1A1A1A;">618活动券展示</text>
<switch :checked="tempCouponInfo.show618Coupon"
@change="(e) => tempCouponInfo.show618Coupon = e.detail.value" color="#E02E24"
style="transform: scale(0.8);" />
</view>
<view v-if="tempCouponInfo.show618Coupon" class="flex-align-center flex-between"
style="margin-bottom: 30rpx;">
<text style="font-size: 30rpx; color: #1A1A1A;">设置618优惠券额度</text>
<input type="text" v-model="tempCouponInfo.coupon618Amount" placeholder="如 188"
style="text-align: right; border: 1px solid #ddd; border-radius: 8rpx; padding: 4rpx 16rpx; width: 140rpx; font-size: 28rpx;" />
</view>
<view style="height: 1px; background-color: #f5f5f5; margin-bottom: 30rpx;"></view>
<view class="flex-align-center flex-between" style="margin-bottom: 30rpx;">
<text style="font-size: 34rpx; font-weight: 500; color: #1A1A1A;">普通优惠券展示</text>
<switch :checked="tempCouponInfo.hasCoupon"
@change="(e) => tempCouponInfo.hasCoupon = e.detail.value" color="#E02E24"
style="transform: scale(0.8);" />
</view>
<scroll-view scroll-y v-if="tempCouponInfo.hasCoupon" class="coupon-options flex-column"
style="max-height: 55vh;">
<view class="coupon-item"
v-for="(img, idx) in ['/static/image/shopping/pdd/coupon1.png', '/static/image/shopping/pdd/coupon2.png', '/static/image/shopping/pdd/coupon3.png']"
:key="idx" @click="tempCouponInfo.couponPath = img"
:style="{ border: tempCouponInfo.couponPath === img ? '4rpx solid #E02E24' : '4rpx solid transparent', marginBottom: '20rpx', borderRadius: '16rpx', overflow: 'hidden', padding: '4rpx' }">
<image :src="img" style="width: 100%; display: block; border-radius: 12rpx;" mode="widthFix">
</image>
</view>
</scroll-view>
<view class="flex-center" style="margin-top: 40rpx;">
<view class="btn primary flex-center"
style="width: 100%; border-radius: 40rpx; padding: 22rpx 0; text-align: center; background-color: #E02E24; color: #fff; font-size: 32rpx; font-weight: 500;"
@click="saveCouponInfo">确认保存</view>
</view>
</view>
</uni-popup>
</view>
</template>
<script setup>
import { ref, computed, getCurrentInstance } from 'vue';
import { onShow, onLoad } from '@dcloudio/uni-app';
import ListCard from './components/list-card/list-card.vue';
import { defaultDataList } from '@/pages/shopping/pdd/json/order.json';
import { util } from '@/utils/common.js';
const { proxy } = getCurrentInstance();
const activeTab = ref(0);
const scrollIntoId = ref('');
// 优惠券配置
const couponInfo = ref({
show618Coupon: true,
coupon618Amount: '188',
hasCoupon: true,
couponPath: '/static/image/shopping/pdd/coupon1.png'
});
const tempCouponInfo = ref({
show618Coupon: true,
coupon618Amount: '188',
hasCoupon: true,
couponPath: '/static/image/shopping/pdd/coupon1.png'
});
const couponPopup = ref(null);
const openCouponPopup = () => {
tempCouponInfo.value = JSON.parse(JSON.stringify(couponInfo.value));
couponPopup.value.open();
};
const saveCouponInfo = () => {
couponInfo.value = JSON.parse(JSON.stringify(tempCouponInfo.value));
uni.setStorageSync('pddCouponInfo', couponInfo.value);
couponPopup.value.close();
uni.showToast({ title: '保存成功', icon: 'success' });
};
//导航栏菜单按钮
const buttonGroup = [
{
name: "新增购物订单",
click: () => {
uni.navigateTo({
url: '/pages/shopping/pdd/add-order/add-order'
});
}
}, {
name: "切换推荐商品图片",
click: () => {
scrollIntoId.value = '';
setTimeout(() => {
scrollIntoId.value = 'bottom-anchor';
}, 50);
setTimeout(() => {
chooseImage();
}, 400);
}
}, {
name: "设置优惠券",
click: () => {
openCouponPopup();
}
}
]
onLoad(() => {
proxy.$apiUserEvent('all', {
type: 'event',
key: 'shopping',
prefix: '.uni.other.',
value: '拼多多'
})
})
const tabList = ref([
{
name: '全部',
id: 0,
value: 'all'
},
{
name: '待付款',
id: 1,
value: 'wait_pay'
},
{
name: '拼团中',
id: 2,
value: 'grouping'
},
{
name: '打包中',
id: 3,
value: 'packing'
},
{
name: '待收货',
id: 4,
value: 'wait_recv'
},
{
name: '评价',
id: 5,
value: 'received'
},
]);
const activeTab2 = ref(0);
const tab2List = ref([
{ name: '全部', count: 1, id: 0 },
{ name: '已签收', count: 0, id: 1 },
{ name: '待取件', count: 0, id: 2 },
{ name: '派件中', count: 0, id: 3 },
{ name: '运输中', count: 1, id: 4 },
{ name: '其他', count: 0, id: 5 },
]);
const displayTab2List = computed(() => {
let sum = 0;
tab2List.value.forEach(item => {
if (item.id !== 0) {
sum += Number(item.count || 0);
}
});
return tab2List.value.map(item => {
if (item.id === 0) {
return { ...item, count: sum };
}
return item;
});
});
const saveTab2List = () => {
uni.setStorageSync('pdd_tab2List', tab2List.value);
uni.showToast({
title: '修改已保存',
icon: 'success'
});
};
const handleTab2Click = (item) => {
if (item.id !== 0) {
// 非“全部”项直接弹窗修改数量,不允许进入选中态
uni.showModal({
title: `修改[${item.name}]数量`,
editable: true,
placeholderText: '请输入数量',
success: (res) => {
if (res.confirm && res.content) {
const num = parseInt(res.content);
if (!isNaN(num) && num >= 0) {
const target = tab2List.value.find(t => t.id === item.id);
if (target) {
target.count = num;
saveTab2List();
}
}
}
}
});
} else {
// 只有点击“全部”本身可以重置或保持激活(尽管业务上可能默认锁死它)
activeTab2.value = item.id;
}
};
const orderList = ref([]);
const showMenu = ref(false);
const menuX = ref(0);
const menuY = ref(0);
const currentEditItem = ref(null);
const handleLongPress = (e, item) => {
const touch = e.touches && e.touches[0] ? e.touches[0] : (e.changedTouches && e.changedTouches[0] ? e.changedTouches[0] : e);
menuX.value = touch.clientX || touch.pageX || 100;
menuY.value = touch.clientY || touch.pageY || 100;
currentEditItem.value = item;
showMenu.value = true;
};
const handleEdit = () => {
showMenu.value = false;
if (currentEditItem.value) {
uni.navigateTo({
url: `/pages/shopping/pdd/add-order/add-order?isEdit=true&id=${currentEditItem.value.id}`
});
}
};
const removeLocalFile = (filePath) => {
if (!filePath) return;
if (filePath.startsWith('http') || filePath.startsWith('/static')) return;
uni.removeSavedFile({
filePath,
fail: () => { }
});
};
const handleDelete = () => {
showMenu.value = false;
if (currentEditItem.value) {
uni.showModal({
title: '提示',
content: '确定要删除该订单吗?',
success: (res) => {
if (res.confirm) {
const index = orderList.value.findIndex(item => item.id === currentEditItem.value.id);
if (index > -1) {
const deletedOrder = orderList.value[index];
// 清理关联的本地缓存图片
if (deletedOrder.shop && deletedOrder.shop.logo) {
removeLocalFile(deletedOrder.shop.logo);
}
if (deletedOrder.products) {
deletedOrder.products.forEach(p => {
if (p.img) removeLocalFile(p.img);
if (p.image) removeLocalFile(p.image);
});
}
if (deletedOrder.avatars) {
deletedOrder.avatars.forEach(av => removeLocalFile(av));
}
orderList.value.splice(index, 1);
// 同步写入缓存
uni.setStorageSync('pddOrderList', orderList.value);
uni.showToast({ title: '删除成功', icon: 'success' });
}
}
}
});
}
};
const getOrderTime = (order) => {
if (order.orderInfo) {
const timeInfo = order.orderInfo.find(info => info.label && info.label.includes('下单时间'));
if (timeInfo && timeInfo.value) {
const timestamp = new Date(timeInfo.value.replace(/-/g, '/')).getTime();
if (!isNaN(timestamp)) {
return timestamp;
}
}
}
return Number(order.id) || 0;
};
const filteredOrderList = computed(() => {
const currentTab = tabList.value.find(t => t.id === activeTab.value);
let list = orderList.value;
if (currentTab && currentTab.value !== 'all') {
list = list.filter(item => item.orderType === currentTab.value);
}
return list.slice().sort((a, b) => getOrderTime(b) - getOrderTime(a));
});
onShow(() => {
const pddCouponInfo = uni.getStorageSync('pddCouponInfo');
if (pddCouponInfo) {
couponInfo.value = pddCouponInfo;
}
const isInitialized = uni.getStorageSync('isPddOrderListInitialized');
if (!isInitialized) {
uni.setStorageSync('pddOrderList', defaultDataList);
uni.setStorageSync('isPddOrderListInitialized', true);
orderList.value = defaultDataList;
} else {
const cacheList = uni.getStorageSync('pddOrderList');
orderList.value = cacheList || [];
}
// 加载拼图截图缓存 (若不存在则初始化默认底图)
let savedScreenshot = uni.getStorageSync('pdd_screenshot');
if (!savedScreenshot) {
savedScreenshot = '/static/image/shopping/pdd/pdd-bottom-product.png';
uni.setStorageSync('pdd_screenshot', savedScreenshot);
}
screenshotImage.value = savedScreenshot;
// 加载二级导航数量缓存
const cachedTab2 = uni.getStorageSync('pdd_tab2List');
if (cachedTab2) {
tab2List.value = cachedTab2;
}
});
// 长按替换截图相关
const screenshotImage = ref('');
const selectedImage = ref('');
const scrollTop = ref(0);
let longPressTimer = null;
// 长按替换截图 - 选择图片
const chooseImage = () => {
if (selectedImage.value) return;
uni.chooseImage({
count: 1,
sourceType: ['album'],
success: (res) => {
selectedImage.value = res.tempFilePaths[0];
}
});
};
// 长按事件
const handleTouchStart = (e) => {
const systemInfo = uni.getSystemInfoSync();
if (systemInfo.platform === 'ios' && systemInfo.safeAreaInsets?.bottom) {
const clientY = e.touches[0].clientY;
const windowHeight = systemInfo.windowHeight;
if (clientY > windowHeight - systemInfo.safeAreaInsets.bottom) {
return;
}
}
longPressTimer = setTimeout(() => {
uni.vibrateShort();
chooseImage();
}, 1200);
};
const handleTouchEnd = () => {
if (longPressTimer) {
clearTimeout(longPressTimer);
longPressTimer = null;
}
};
// 图片滚动
const onImageScroll = (e) => {
scrollTop.value = e.detail.scrollTop;
};
// 确认图片裁剪
const confirmImage = () => {
uni.showLoading({
title: '处理中...'
})
const query = uni.createSelectorQuery().in(proxy)
// 获取容器和图片信息
query.select('.image-box').boundingClientRect()
query.select('.crop-image-target').boundingClientRect()
query.exec(res => {
if (!res[0] || !res[1]) {
uni.hideLoading()
return
}
console.log('rects', res)
const container = res[0] // 容器
const image = res[1] // 图片实际渲染尺寸
// 计算缩放比例 (渲染宽度 / 实际宽度 不准确,应该反过来用 图片原始宽/渲染宽?)
// 这里更简单的方法是canvas设为容器大小把图片画进去
// canvas drawImage 参数: img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight
// 获取图片原始尺寸
uni.getImageInfo({
src: selectedImage.value,
success: (imgInfo) => {
const scale = imgInfo.width / image.width // 图片 原始宽 / 渲染宽
const sTop = scrollTop.value * scale // 原始图上的裁切起始Y
const sHeight = container.height * scale // 原始图上的裁切高度
// 因为是 widthFix宽度就是原始图宽度或裁切全宽
const sWidth = imgInfo.width
// 设置画布尺寸 (使用像素值)
// 注意canvasContext绘制使用的是逻辑像素还是物理像素通常需要考虑到 pixelRatio
// 但 uni-app canvas-id 方式通常对应逻辑像素(px)
// 我们把 canvas 大小设为和容器显示一致
const canvasW = container.width
const canvasH = container.height
const ctx = uni.createCanvasContext('crop-canvas', proxy)
// 清除画布
ctx.clearRect(0, 0, canvasW, canvasH)
// 绘制
// drawImage(imageResource, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
ctx.drawImage(
imgInfo.path,
0, sTop, sWidth, sHeight, // 源图裁剪区域
0, 0, canvasW, canvasH // 画布绘制区域
)
ctx.draw(false, () => {
uni.canvasToTempFilePath({
canvasId: 'crop-canvas',
width: canvasW,
height: canvasH,
destWidth: sWidth, // 使用原图实际宽度,保持原图清晰度
destHeight: sHeight, // 使用原图实际高度,保持原图清晰度
success: (res) => {
console.log('crop success (temp)', res
.tempFilePath)
// 将临时路径保存为永久路径
uni.saveFile({
tempFilePath: res.tempFilePath,
success: (saveRes) => {
console.log('save success (saved)', saveRes.savedFilePath)
screenshotImage.value = saveRes.savedFilePath
selectedImage.value = '' // 隐藏编辑模式
setTimeout(() => {
plus.navigator.setStatusBarStyle("light");
}, 200)
// 保存到缓存
uni.setStorageSync('pdd_screenshot', screenshotImage.value)
uni.hideLoading()
},
fail: (err) => {
console.error('saveFile fail', err)
uni.hideLoading()
uni.showToast({
title: '保存失败',
icon: 'none'
})
}
})
},
fail: (err) => {
console.error(err)
uni.hideLoading()
uni.showToast({
title: '裁剪失败',
icon: 'none'
})
}
}, proxy)
})
},
fail: () => {
uni.hideLoading()
uni.showToast({
title: '图片加载失败',
icon: 'none'
})
}
})
})
}
// 关闭截图预览
const closeImage = () => {
selectedImage.value = '';
};
</script>
<style lang="less" scoped>
.page-container {
height: 100vh;
}
.nav-bar {
border-bottom: 1rpx solid #D2D2D2;
}
.title-box {
display: flex;
flex-direction: column;
.title {
font-weight: 400;
font-size: 30rpx;
color: #1A1A1A;
line-height: 30rpx;
}
.text {
font-weight: 400;
font-size: 24rpx;
color: #16B800;
line-height: 24rpx;
margin-top: 12rpx;
}
}
.tab-list {
height: 80rpx;
background-color: #ffff;
border-bottom: 0.5px solid #D2D2D2;
.tab-item {
font-weight: 400;
font-size: 30rpx;
color: #1A1A1A;
line-height: 80rpx;
white-space: nowrap;
margin: 0 22rpx;
&.active {
color: #E01B13;
font-weight: 500;
box-shadow: inset 0 -4rpx 0 0 #E01B13;
}
}
}
.tab2-box {
height: 78rpx;
background-color: #ffff;
border-bottom: 0.5px solid #D2D2D2;
width: 100%;
white-space: nowrap;
:deep(.uni-scroll-view::-webkit-scrollbar) {
display: none !important;
width: 0 !important;
height: 0 !important;
-webkit-appearance: none;
background: transparent;
}
.tab2-content {
display: inline-flex;
padding: 0 24rpx;
height: 100%;
}
.tab2-item {
flex-shrink: 0;
height: 52rpx;
padding: 0 16rpx;
background-color: #F8F8F8;
border-radius: 26rpx;
margin-right: 20rpx;
font-size: 26rpx;
color: #1A1A1A;
white-space: nowrap;
&.active {
background-color: #FCEFEF;
font-weight: 500;
color: #E01B13;
}
}
}
.null-data-box {
justify-content: center;
font-size: 28rpx;
color: #999999;
line-height: 28rpx;
padding: 42rpx 0;
}
.menu-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 998;
}
.context-menu {
position: fixed;
z-index: 999;
background-color: #fff;
border-radius: 8rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
width: 200rpx;
overflow: hidden;
.menu-item {
height: 80rpx;
line-height: 80rpx;
text-align: center;
font-size: 28rpx;
color: #333;
border-bottom: 1rpx solid #F5F5F5;
&:last-child {
border-bottom: none;
}
&.text-red {
color: #DF2E26;
}
}
}
.bottom-fixed {
display: flex;
flex-direction: column;
.upload-screenshot-box {
width: 100%;
flex: 1;
min-height: 540rpx;
background-color: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
position: relative;
.upload-screenshot {
width: 92rpx;
height: 92rpx;
}
.upload-screenshot-content {
width: 100%;
height: 100%;
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
.upload-screenshot-text {
font-size: 36rpx;
color: #1777FF;
line-height: 50rpx;
margin-top: 16rpx;
}
}
.screenshot-preview-box {
width: 100%;
height: 100%;
display: flex;
align-items: flex-start;
// flex-direction: column;
justify-content: center;
.screenshot-preview {
width: 100%;
height: 100%;
}
}
.scroll-image-box {
width: 100%;
min-height: 0; // 修复 flex一出问题
// overflow: hidden; // scroll-view 需要
position: relative;
}
.dashed-line-box {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
border: 4rpx dashed #ffffff;
pointer-events: none;
.dashed-line-text {
height: 44rpx;
line-height: 44rpx;
width: 180rpx;
padding: 0 20rpx;
border-radius: 8rpx;
color: #1777FF;
font-size: 24rpx;
font-weight: 500;
background-color: #fff;
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%, -50%);
}
}
.mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.8);
z-index: 999;
.mask-icon {
position: absolute;
top: 50%;
right: 52rpx;
transform: translateY(-25%);
width: 360rpx;
height: 360rpx;
}
}
}
}
.coupon-banner {
background-color: #FEF5B2;
padding: 20rpx 22rpx;
font-weight: 400;
font-size: 26rpx;
color: #1A1A1A;
line-height: 26rpx;
.red {
color: #DF2E26;
}
}
</style>
<style>
@import '@/common/main.css';
page {
background-color: #F5F5F5;
}
</style>