feat: update

This commit is contained in:
chashaobao
2025-10-20 07:58:50 +08:00
parent bc141fcf1b
commit a179654898
32 changed files with 648 additions and 271 deletions

View File

@ -2,26 +2,53 @@
@import '@/styles/common.less';
.partner-intro {
padding-top: 112px;
padding-bottom: calc(112px + constant(safe-area-inset-bottom));
padding-bottom: calc(112px + env(safe-area-inset-bottom));
background: #eae5fb;
padding-top: 271px;
position: relative;
padding-bottom: calc(142px + constant(safe-area-inset-bottom));
padding-bottom: calc(142px + env(safe-area-inset-bottom));
&__banner {
background: rgb(229, 225, 248);
height: 88px;
line-height: 88px;
text-align: center;
font-size: 28px;
position: fixed;
top: 98px;
&__bg {
width: 100%;
height: 705px;
position: absolute;
top: 0;
left: 0;
right: 0;
width: 100vw;
}
&__slogan {
top: 66px;
left: 44px;
position: absolute;
font-family: 'Alimama ShuHeiTi';
font-style: normal;
font-weight: 700;
font-size: 44px;
line-height: 62px;
color: #333333;
> div {
margin-bottom: 12px;
}
&-highlight {
display: inline-block;
padding-left: 12px;
padding-right: 9px;
font-size: 64px;
line-height: 62px;
background: linear-gradient(87.53deg, #683DE3 0.4%, #39227D 84.55%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-fill-color: transparent;
}
}
&__main {
padding-left: 24px;
padding-right: 24px;
position: relative;
z-index: 1;
}
&__highlight {
@ -34,15 +61,17 @@
}
&__block {
margin-bottom: 40px;
margin-bottom: 12px;
position: relative;
}
&__swiper {
margin-bottom: 48px;
&-wrapper {
margin-bottom: 8px;
background: #fff;
border-radius: 24px;
position: relative;
border: 1px solid #6d3df5;
}
&-bg {
@ -54,12 +83,11 @@
}
}
&__swiper-item {
box-sizing: border-box;
height: 130px;
padding: 24px 32px;
&-item {
&-time {
font-style: normal;
font-size: 28px;
line-height: 40px;
@ -98,7 +126,7 @@
&__card {
background: #fff;
border-radius: 24px;
padding: 24px 32px;
padding: 68px 32px 44px;
}
&__h1 {
@ -108,10 +136,30 @@
color: #1d2129;
margin-bottom: 16px;
margin-top: 32px;
position: relative;
z-index: 0;
&.no-dot {
&:after {
background: transparent;
}
}
&:first-child {
margin-top: 0;
}
&:after {
content: '';
width: 28px;
height: 28px;
background: #ffd236;
border-radius: 50%;
position: absolute;
left: -6px;
top: -3px;
z-index: -1;
}
}
&__body {
@ -130,12 +178,19 @@
}
&__title {
margin-bottom: 24px;
margin-left: 48px;
margin-right: 48px;
font-weight: 500;
font-size: 32px;
line-height: 32px;
line-height: 80px;
height: 80px;
transform: translateY(50%);
background: #ffd236;
box-shadow: 0px 12px 0px #ffa35d;
border-radius: 60px;
color: #1d2129;
text-align: center;
position: relative;
}
&__recommend {
@ -143,17 +198,19 @@
line-height: 36px;
padding: 0 8px;
height: 36px;
margin-left: 16px;
background: rgba(255, 80, 81, 0.12);
background: rgb(255, 80, 81);
border-radius: 4px;
font-size: 24px;
color: #ff5051;
color: #fff;
align-items: center;
position: absolute;
gap: 6px;
right: -25px;
top: -18px;
}
&__special {
padding: 32px;
padding-top: 75px;
.flex-column();
.partner-intro__body {
@ -176,6 +233,7 @@
&__footer {
position: fixed;
bottom: 0;
z-index: 2;
width: 100vw;
background: #ffffff;
padding: 12px 32px;
@ -188,17 +246,20 @@
display: flex;
flex-direction: row;
box-sizing: border-box;
justify-content: center;
}
&__download-button {
flex: 1 1;
//flex: 1 1;
.button(@height: 88px; @fontSize: 32px; @fontWeight: 500; @borderRadius: 44px; @highlight: 0);
}
&__share-button {
flex: 2 2;
//flex: 2 2;
flex: 0 0 406px;
width: 406px;
.button(@height: 88px; @fontSize: 32px; @fontWeight: 500; @borderRadius: 44px;);
margin-left: 32px;
//margin-left: 32px;
}
}

View File

@ -1,5 +1,4 @@
import { Button, Canvas, Image } from '@tarojs/components';
import Taro from '@tarojs/taro';
import { Swiper } from '@taroify/core';
import { GoodJob } from '@taroify/icons';
@ -8,114 +7,14 @@ import { useCallback, useEffect, useRef, useState } from 'react';
import { PageUrl } from '@/constants/app';
import { EarnType, UserProfitListItem } from '@/types/partner';
import { openCustomerServiceChat } from '@/utils/common';
import { generateMembershipCoupon, getCouponQrCode } from '@/utils/coupon';
import { formatMoney, formatTimestamp, getLastProfitList } from '@/utils/partner';
import { formatMoney, formatTimestamp, formatUserId, getLastProfitList } from '@/utils/partner';
import { navigateTo } from '@/utils/route';
import './index.less';
const PREFIX = 'partner-intro';
export default function PartnerIntro() {
const getQrcode = async () => {
try {
const { code } = await generateMembershipCoupon();
const data = await getCouponQrCode(code);
const base64 = Taro.arrayBufferToBase64(data);
return `data:image/png;base64,${base64}`;
} catch (error) {
console.error('获取二维码失败', error);
Taro.showToast({ title: '获取二维码失败', icon: 'none' });
throw error;
}
};
const saveCanvasToTempFile = (): Promise<string> => {
return new Promise((resolve, reject) => {
try {
const query = Taro.createSelectorQuery().select('#posterCanvas');
query.fields({ node: true }).exec(async res => {
const canvas = res[0].node;
const tempFilePath = await Taro.canvasToTempFilePath({
canvas,
x: 0,
y: 0,
width: 1500, // 实际绘制宽度
height: 2668, // 实际绘制高度
destWidth: 750, // 目标显示宽度
destHeight: 1334, // 目标显示高度
fileType: 'png',
});
resolve(tempFilePath.tempFilePath);
});
} catch (error) {
console.error('保存 Canvas 到临时文件失败', error);
Taro.showToast({ title: '保存 Canvas 失败', icon: 'none' });
reject(error);
}
});
};
const drawCanvas = (qrCode: string): Promise<string> => {
const query = Taro.createSelectorQuery().select('#posterCanvas');
return new Promise(resolve => {
query.fields({ node: true, size: true }).exec(async res => {
const canvas = res[0].node;
const ctx = canvas.getContext('2d');
canvas.width = 550 * 2;
canvas.height = 918 * 2;
ctx.scale(2, 2);
// 绘制背景图片
const bgImage = canvas.createImage();
const poster = 'https://publiccdn.neighbourhood.com.cn/img/share-coupon-poster2.png';
bgImage.src = poster;
bgImage.onload = () => {
ctx.drawImage(bgImage, 0, 0, 550, 918);
const qrCodeImage = canvas.createImage();
qrCodeImage.src = qrCode; // 假设 getQrcode() 返回的是二维码图片的路径
qrCodeImage.onload = () => {
ctx.drawImage(qrCodeImage, 196, 600, 180, 160); // 绘制二维码,位置和大小
saveCanvasToTempFile().then(tempPath => {
resolve(tempPath);
});
};
};
bgImage.onerror = err => {
console.error(err);
};
});
});
};
const savePoster = async () => {
Taro.showLoading({ title: '正在生成海报' });
const qrCode = await getQrcode();
const filePath = await drawCanvas(qrCode);
Taro.hideLoading();
const res = await Taro.getSetting();
const hasPermission = res.authSetting['scope.writePhotosAlbum'];
if (hasPermission === false) {
Taro.showModal({
title: '提示',
content: '需要访问相册权限才能保存图片,请前往设置开启权限',
showCancel: false,
success() {
Taro.openSetting();
},
});
} else {
try {
await Taro.authorize({ scope: 'scope.writePhotosAlbum' });
await Taro.saveImageToPhotosAlbum({ filePath });
Taro.showToast({ title: '保存成功', icon: 'success' });
} catch (error) {
console.error(error);
Taro.showToast({ title: '保存失败', icon: 'none' });
}
}
};
const handleConfirm = useCallback(() => {
navigateTo(PageUrl.GroupOwnerCertificate);
}, []);
@ -124,6 +23,10 @@ export default function PartnerIntro() {
openCustomerServiceChat('https://work.weixin.qq.com/kfid/kfc4fcf6b109b3771d7');
}, []);
const handleJump = useCallback(() => {
navigateTo(PageUrl.PartnerShareVip);
}, []);
const timerRef = useRef<NodeJS.Timeout | null>(null);
const [bannerList, setBannerList] = useState<UserProfitListItem[]>([]);
@ -134,7 +37,7 @@ export default function PartnerIntro() {
}
const list = await getLastProfitList();
setBannerList(s => [...s, ...list]);
setBannerList(list);
timerRef.current = setTimeout(
() => {
@ -156,8 +59,16 @@ export default function PartnerIntro() {
}, [getBannerList]);
return (
<div className={PREFIX}>
<div className={`${PREFIX}__banner`}>
<span className={`${PREFIX}__highlight`}>75%</span>
<Image
src="https://publiccdn.neighbourhood.com.cn/img/partner-intro-bg.png"
className={`${PREFIX}__bg`}
mode="aspectFill"
/>
<div className={`${PREFIX}__slogan`}>
<div></div>
<div>
<div className={`${PREFIX}__slogan-highlight`}>75%</div>
</div>
</div>
<div className={`${PREFIX}__main`}>
<div className={`${PREFIX}__swiper-wrapper`}>
@ -168,10 +79,10 @@ export default function PartnerIntro() {
/>
<Swiper className={`${PREFIX}__swiper`} autoplay={3000} touchable={false}>
{bannerList.map((item, index) => (
<Swiper.Item className={`${PREFIX}__swiper-item`} key={index}>
<Swiper.Item className={`${PREFIX}__swiper-item`} key={`${item.userId}-${index}`}>
<div className={`${PREFIX}__swiper-item-time`}>{formatTimestamp(item.updatedAt)}</div>
<div className={`${PREFIX}__swiper-item-details`}>
<div className={`${PREFIX}__swiper-item-id`}>{item.userId}</div>
<div className={`${PREFIX}__swiper-item-id`}>{formatUserId(item.userId)}</div>
<div className={`${PREFIX}__swiper-item-info`}>
{[EarnType.CHAT_ACTIVITY_SHARE_L1, EarnType.CHAT_ACTIVITY_SHARE_L2].includes(item.earnType)
? '主播被开聊'
@ -187,6 +98,25 @@ export default function PartnerIntro() {
</Swiper>
</div>
<div className={`${PREFIX}__block`}>
<div className={`${PREFIX}__title`}>
<div className={`${PREFIX}__recommend`}>
<GoodJob />
</div>
</div>
<div className={`${PREFIX}__card ${PREFIX}__special`}>
<div className={`${PREFIX}__body`}>
<div className="center">
访
</div>
</div>
<Button className={`${PREFIX}__service`} onClick={handleConfirm}>
</Button>
</div>
</div>
<div className={`${PREFIX}__block`}>
<div className={`${PREFIX}__title`}>3</div>
<div className={`${PREFIX}__card`}>
@ -209,34 +139,17 @@ export default function PartnerIntro() {
<div className={`${PREFIX}__title`}></div>
<div className={`${PREFIX}__card`}>
<div className={`${PREFIX}__body`}>
<div>1.</div>
<div>2.</div>
<div className={`${PREFIX}__h1`}></div>
<div></div>
<div className={`${PREFIX}__h1`}></div>
<div></div>
</div>
</div>
</div>
<div className={`${PREFIX}__block`}>
<div className={`${PREFIX}__title`}>
<div className={`${PREFIX}__recommend`}>
<GoodJob />
</div>
</div>
<div className={`${PREFIX}__card ${PREFIX}__special`}>
<div className={`${PREFIX}__body`}>
<div className="center">
访
</div>
</div>
<Button className={`${PREFIX}__service`} onClick={handleConfirm}>
</Button>
</div>
</div>
<div className={`${PREFIX}__block`}>
<div className={`${PREFIX}__title`}></div>
<div className={`${PREFIX}__card ${PREFIX}__special`}>
<div className={`${PREFIX}__h1`}></div>
<div className={`${PREFIX}__h1 no-dot`}></div>
<Button className={`${PREFIX}__service`} onClick={handleOpenService}>
</Button>
@ -246,10 +159,7 @@ export default function PartnerIntro() {
<Canvas id="posterCanvas" canvas-id="posterCanvas" type="2d" style="width: 750px; height: 1334px;" />
<div className={`${PREFIX}__footer`}>
<Button className={`${PREFIX}__download-button`} onClick={savePoster}>
</Button>
<Button className={`${PREFIX}__share-button`} openType="share">
<Button className={`${PREFIX}__share-button`} onClick={handleJump}>
</Button>
</div>