feat: 生成海报

This commit is contained in:
2025-10-03 09:19:05 +08:00
parent 40a043d2a0
commit 5fec10b342
18 changed files with 1032 additions and 200 deletions

View File

@@ -6,7 +6,6 @@ import React, {
forwardRef,
} from "react";
import { View, Text, Image, Map, ScrollView, Button } from "@tarojs/components";
// import { Avatar } from "@nutui/nutui-react-taro";
import Taro, {
useRouter,
useShareAppMessage,
@@ -25,6 +24,7 @@ import {
Comments,
Poster,
} from "@/components";
import { generateShareImage, generatePosterImage } from "@/utils";
import DetailService, {
MATCH_STATUS,
IsSubstituteSupported,
@@ -35,6 +35,12 @@ import { getCurrentLocation, calculateDistance } from "@/utils/locationUtils";
import { useUserInfo, useUserActions } from "@/store/userStore";
import { EvaluateCallback, EvaluateScene } from "@/store/evaluateStore";
import img from "@/config/images";
import DownloadIcon from "@/static/detail/download_icon.svg";
import WechatLogo from "@/static/detail/wechat_icon.svg";
import WechatTimeline from "@/static/detail/wechat_timeline.svg";
import LinkIcon from "@/static/detail/link.svg";
import CrossIcon from "@/static/detail/cross.svg";
import { DayOfWeekMap } from "./config";
import styles from "./style.module.scss";
import "./index.scss";
@@ -173,100 +179,281 @@ function Coursel(props) {
);
}
// 分享弹窗
const SharePopup = forwardRef(
({ id, from }: { id: string; from: string }, ref) => {
const [visible, setVisible] = useState(true);
useImperativeHandle(ref, () => ({
show: () => {
setVisible(true);
},
}));
useShareAppMessage((res) => {
console.log(res, "res");
return {
title: "分享",
imageUrl: "https://img.yzcdn.cn/vant/cat.jpeg",
path: `/game_pages/detail/index?id=${id}&from=share`,
};
});
// function handleShareToWechatMoments() {
// useShareTimeline(() => {
// return {
// title: '分享',
// path: `/game_pages/detail/index?id=${id}&from=share`,
// }
// })
// }
function handleSaveToLocal() {
Taro.showToast({ title: "not yet", icon: "error" });
return;
Taro.saveImageToPhotosAlbum({
filePath: "",
success: () => {
Taro.showToast({ title: "保存成功", icon: "success" });
},
fail: () => {
Taro.showToast({ title: "保存失败", icon: "none" });
},
const PosterPopup = forwardRef((props, ref) => {
const [visible, setVisible] = useState(false);
const [posterData, setPosterData] = useState();
const posterRef = useRef();
useImperativeHandle(ref, () => ({
show: (detail, user) => {
setVisible(true);
const {
play_type,
skill_level_max,
skill_level_min,
image_list,
title,
start_time,
end_time,
location_name,
} = detail;
const { avatar_url, nickname } = user;
const startTime = dayjs(start_time);
const endTime = dayjs(end_time);
const dayofWeek = DayOfWeekMap.get(startTime.day());
const gameLength = `${endTime.diff(startTime, "hour")}小时`;
setPosterData({
playType: play_type,
ntrp: `NTRP ${genNTRPRequirementText(
skill_level_min,
skill_level_max
)}`,
mainCoursal:
image_list[0] ||
"https://bimwe.oss-cn-shanghai.aliyuncs.com/front/ball/images/0621b8cf-f7d6-43ad-b852-7dc39f29a782.png",
nickname,
avatarUrl: avatar_url,
title,
locationName: location_name,
date: `${startTime.format("M月D日")} (${dayofWeek})`,
time: `${startTime.format("ah")}${gameLength}`,
});
}
},
}));
return (
<>
{/* <CommonPopup
title="分享至"
visible={visible}
onClose={() => {
setVisible(false);
}}
hideFooter
style={{ minHeight: "100px" }}
>
<View className={styles.shareContainer}>
<View catchMove className={styles.title}>
分享至
</View>
<View className={styles.shareItems}>
<Button
className={classnames(styles.button, styles.share)}
openType="share"
>
微信好友
</Button>
<Button
className={classnames(styles.button, styles.save)}
onClick={handleSaveToLocal}
>
生成分享图
</Button>
</View>
</View>
</CommonPopup> */}
<CommonPopup
title="分享至"
visible={visible}
onClose={() => {
setVisible(false);
}}
showHeader={false}
position="center"
hideFooter
enableDragToClose={false}
style={{ minHeight: "100px" }}
>
<View className={styles.posterWrap}>
<Poster />
</View>
</CommonPopup>
</>
);
useShareAppMessage(async () => {
const tempFilePath = await posterRef.current.generateImage();
return {
// title: detail.title,
imageUrl: tempFilePath,
path: `/game_pages/detail/index?id=${props.id}&from=share`,
};
});
useShareTimeline(async () => {
const tempFilePath = await posterRef.current.generateImage();
return {
title: "分享",
imageUrl: tempFilePath,
path: `/game_pages/detail/index?id=${props.id}&from=share`,
};
});
function onClose() {
setVisible(false);
setPosterData(undefined);
Taro.updateShareMenu({
isUpdatableMessage: true, // 是否是动态消息(需要服务端配置过模版)
});
}
);
async function handleShare() {
const tempFilePath = await posterRef.current.generateImage();
Taro.showShareImageMenu({
path: tempFilePath,
});
}
return (
visible && (
<CommonPopup
title="分享至"
visible={visible}
onClose={onClose}
showHeader={false}
position="center"
hideFooter
enableDragToClose={false}
style={{ minHeight: "100px" }}
zIndex={2001}
>
<View className={styles.posterContainer}>
<View className={styles.posterWrap}>
{posterData && <Poster ref={posterRef} data={posterData} />}
</View>
<View className={styles.sharePoster}>
<Button className={styles.shareItem} plain={true}>
<View className={styles.icon}>
<Image className={styles.download} src={DownloadIcon} />
</View>
<Text></Text>
</Button>
<Button
className={styles.shareItem}
plain={true}
onClick={handleShare}
>
<View className={classnames(styles.icon, styles.wechatIcon)}>
<Image className={styles.wechat} src={WechatLogo} />
</View>
<Text></Text>
</Button>
<Button className={styles.shareItem} plain={true} openType="share">
<View className={styles.icon}>
<Image className={styles.timeline} src={WechatTimeline} />
</View>
<Text></Text>
</Button>
</View>
</View>
</CommonPopup>
)
);
});
// 分享弹窗
const SharePopup = forwardRef(({ id, from, detail, userInfo }, ref) => {
const [visible, setVisible] = useState(false);
const posterRef = useRef();
useEffect(() => {
changeMessageType();
}, []);
async function changeMessageType() {
try {
const res = await DetailService.getActivityId({
business_id: id,
business_type: "game",
is_private: false,
});
if (res.code === 0) {
Taro.updateShareMenu({
withShareTicket: false, // 是否需要返回 shareTicket
isUpdatableMessage: true, // 是否是动态消息(需要服务端配置过模版)
activityId: res.data.activity_id, // 动态消息的活动 id
});
}
} catch (e) {
Taro.showToast({ title: e.message, icon: "none" });
}
}
useImperativeHandle(ref, () => ({
show: () => {
setVisible(true);
},
}));
useShareAppMessage(async (res) => {
const {
play_type,
skill_level_max,
skill_level_min,
start_time,
end_time,
location_name,
venue_image_list,
} = detail || {};
const startTime = dayjs(start_time);
const endTime = dayjs(end_time);
const dayofWeek = DayOfWeekMap.get(startTime.day());
const gameLength = `${endTime.diff(startTime, "hour")}小时`;
const url = await generateShareImage({
userAvatar: userInfo.avatar_url,
userNickname: userInfo.nickname,
gameType: play_type,
skillLevel: `NTRP ${genNTRPRequirementText(
skill_level_min,
skill_level_max
)}`,
gameDate: `${startTime.format("M月D日")} (${dayofWeek})`,
gameTime: `${startTime.format("ah")}${gameLength}`,
venueName: location_name,
venueImages: venue_image_list ? venue_image_list.map((c) => c.url) : [],
});
// console.log(res, "res");
return {
title: detail.title,
imageUrl: url || "https://img.yzcdn.cn/vant/cat.jpeg",
path: `/game_pages/detail/index?id=${id}&from=share`,
};
});
async function handlePost() {
const {
play_type,
skill_level_max,
skill_level_min,
start_time,
end_time,
location_name,
image_list,
title,
} = detail || {};
const { avatar_url, nickname } = userInfo;
const startTime = dayjs(start_time);
const endTime = dayjs(end_time);
const dayofWeek = DayOfWeekMap.get(startTime.day());
const gameLength = `${endTime.diff(startTime, "hour")}小时`;
Taro.showLoading({ title: "生成中..." });
const url = await generatePosterImage({
playType: play_type,
ntrp: `NTRP ${genNTRPRequirementText(skill_level_min, skill_level_max)}`,
mainCoursal:
image_list[0] ||
"https://bimwe.oss-cn-shanghai.aliyuncs.com/front/ball/images/0621b8cf-f7d6-43ad-b852-7dc39f29a782.png",
nickname,
avatarUrl: avatar_url,
title,
locationName: location_name,
date: `${startTime.format("M月D日")} (${dayofWeek})`,
time: `${startTime.format("ah")}${gameLength}`,
});
Taro.hideLoading();
setVisible(false);
Taro.showShareImageMenu({
path: url,
});
}
function onClose() {
setVisible(false);
}
return (
<>
<CommonPopup
title="分享至"
visible={visible}
onClose={onClose}
showHeader={false}
hideFooter
enableDragToClose={false}
style={{ minHeight: "100px" }}
zIndex={1000}
>
<View className={styles.shareContainer}>
<View catchMove className={styles.title}>
<Text></Text>
<View className={styles.closeIconWrap} onClick={onClose}>
<Image className={styles.closeIcon} src={CrossIcon} />
</View>
</View>
<View className={styles.shareItems}>
<Button className={styles.button} openType="share">
<View className={classnames(styles.icon, styles.wechatIcon)}>
<Image className={styles.wechat} src={WechatLogo} />
</View>
<Text></Text>
</Button>
<Button className={styles.button} onClick={handlePost}>
<View className={styles.icon}>
<Image className={styles.download} src={DownloadIcon} />
</View>
<Text></Text>
</Button>
<Button className={styles.button}>
<View className={styles.icon}>
<Image className={styles.linkIcon} src={LinkIcon} />
</View>
<Text></Text>
</Button>
</View>
</View>
</CommonPopup>
{/* <PosterPopup ref={posterRef} id={detail.id} /> */}
</>
);
});
function navto(url) {
Taro.navigateTo({
@@ -1346,6 +1533,8 @@ function Index() {
ref={sharePopupRef}
id={id as string}
from={from as string}
detail={detail}
userInfo={userInfo}
/>
</View>
</View>