feat: 生成分享图

This commit is contained in:
2025-10-15 11:20:36 +08:00
parent 56fd71f266
commit 77e50731a3
30 changed files with 2756 additions and 2641 deletions

View File

@@ -0,0 +1,6 @@
export default definePageConfig({
navigationBarTitleText: '生成分享图',
navigationStyle: 'custom',
enableShareAppMessage: true,
enableShareTimeline: true,
})

View File

@@ -0,0 +1,101 @@
.navbar {
box-shadow: none;
}
.posterContainer {
width: 100vw;
height: 100vh;
background: linear-gradient(180deg, #fff 0%, #fafafa 100%), #fff;
padding: 100px 20px 40px;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
// gap: 20px;
}
.posterWrap {
width: 100%;
border-radius: 19.067px;
// border: 1px solid rgba(0, 0, 0, 0.06);
// background: linear-gradient(180deg, #bfffef 0%, #f2fffc 100%), #fff;
// box-shadow: 0 6.933px 55.467px 0 rgba(0, 0, 0, 0.1);
// overflow: hidden;
box-sizing: border-box;
.imageContainer {
width: 100%;
padding: 0 20px;
box-sizing: border-box;
.poster {
border-radius: 12px;
box-shadow: 0 6.933px 55.467px 0 rgba(0, 0, 0, 0.1);
width: 100%;
}
}
}
.sharePoster {
width: 100%;
margin-top: 40px;
display: flex;
align-items: center;
justify-content: space-around;
.shareItem {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
gap: 12px;
color: rgba(0, 0, 0, 0.85);
font-feature-settings: "liga" off, "clig" off;
font-family: "PingFang SC";
font-size: 14px;
font-style: normal;
font-weight: 600;
line-height: normal;
background-color: #fff;
border: none;
padding: 0;
margin: 0;
line-height: normal;
font-size: inherit;
color: inherit;
&:after {
border: none;
background: transparent;
}
.icon {
width: 64px;
height: 64px;
border-radius: 50%;
background-color: #fff;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid rgba(0, 0, 0, 0.06);
box-shadow: 0 8px 64px 0 rgba(0, 0, 0, 0.1);
&.wechatIcon {
background-color: #07c160;
}
.download {
width: 28px;
height: 28px;
}
.wechat {
width: 36px;
height: 30px;
}
.timeline {
width: 32px;
height: 32px;
}
}
}
}

View File

@@ -0,0 +1,134 @@
// import React from "react";
import { useState, useEffect } from "react";
import { View, Image, Text, Button } from "@tarojs/components";
import Taro, { useRouter } from "@tarojs/taro";
import classnames from "classnames";
import dayjs from "dayjs";
import { generatePosterImage, base64ToTempFilePath, delay } from "@/utils";
import { withAuth } from "@/components";
import GeneralNavbar from "@/components/GeneralNavbar";
import DetailService from "@/services/detailService";
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 { useUserActions } from "@/store/userStore";
import { DayOfWeekMap } from "../detail/config";
import { genNTRPRequirementText } from "@/game_pages/detail/utils/helper";
import styles from "./index.module.scss";
function SharePoster(props) {
const [url, setUrl] = useState("");
const { fetchUserInfo } = useUserActions();
const { id } = useRouter().params;
useEffect(() => {
fetchDetail();
}, []);
async function fetchDetail() {
const res = await DetailService.getDetail(Number(id));
handleGenPoster(res.data);
}
async function handleGenPoster(detail) {
const {
id,
play_type,
skill_level_max,
skill_level_min,
start_time,
end_time,
location_name,
image_list,
title,
} = detail || {};
const userInfo = await fetchUserInfo();
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 qrCodeUrlRes = await DetailService.getQrCodeUrl({
page: "game_pages/detail/index",
scene: `id=${id}`,
});
const qrCodeUrl = await base64ToTempFilePath(
qrCodeUrlRes.data.qr_code_base64
);
await delay(100);
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}`,
qrCodeUrl,
});
Taro.hideLoading();
setUrl(url);
}
function handleShare() {
Taro.showShareImageMenu({
path: url,
});
}
return (
<>
<GeneralNavbar
title="生成分享图"
backgroundColor="transparent"
className={styles.navbar}
/>
{url && (
<View className={styles.posterContainer}>
<View className={styles.posterWrap}>
<View className={styles.imageContainer}>
<Image className={styles.poster} src={url} mode="widthFix" />
</View>
</View>
<View className={styles.sharePoster}>
<Button
className={styles.shareItem}
plain={true}
onClick={handleShare}
>
<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}
onClick={handleShare}
>
<View className={styles.icon}>
<Image className={styles.timeline} src={WechatTimeline} />
</View>
<Text></Text>
</Button>
</View>
</View>
)}
</>
);
}
export default withAuth(SharePoster);