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,132 @@
.detail-page-content-participants {
padding: 24px 15px 0;
box-sizing: border-box;
.participants-title {
display: flex;
padding-bottom: 6px;
align-items: center;
overflow: hidden;
color: #fff;
font-feature-settings: "liga" off, "clig" off;
text-overflow: ellipsis;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: 24px; /* 150% */
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.participants-list {
padding: 10px 0 0;
height: 162px;
display: flex;
flex-direction: row;
gap: 8px;
&-application {
display: flex;
width: 108px;
height: 162px;
padding: 16px 12px 10px 12px;
box-sizing: border-box;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 8px;
align-self: stretch;
border-radius: 20px;
border: 1px dashed rgba(255, 255, 255, 0.2);
background: rgba(255, 255, 255, 0.16);
flex: 0 0 auto;
&-icon {
width: 28px;
height: 28px;
}
&-text {
color: rgba(255, 255, 255, 0.6);
font-feature-settings: "liga" off, "clig" off;
font-family: "PingFang SC";
font-size: 12px;
font-style: normal;
font-weight: 500;
line-height: 20px; /* 166.667% */
}
}
&-scroll {
flex: 0 0 auto;
width: calc(100% - 116px);
&-content {
display: flex;
flex-direction: row;
gap: 8px;
height: 162px;
flex-wrap: nowrap;
.participants-list-item {
display: flex;
width: 108px;
padding: 16px 4px 10px 4px;
box-sizing: border-box;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 4px;
border-radius: 20px;
border: 0.5px solid rgba(255, 255, 255, 0.2);
background: rgba(255, 255, 255, 0.16);
flex: 0 0 auto;
.participants-list-item-avatar {
width: 60px;
height: 60px;
border-radius: 50%;
overflow: hidden;
}
&-name {
width: 100%;
color: rgba(255, 255, 255, 0.85);
text-align: center;
font-feature-settings: "liga" off, "clig" off;
font-family: "PingFang SC";
font-size: 13px;
font-style: normal;
font-weight: 500;
line-height: 24px; /* 184.615% */
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&-level {
color: rgba(255, 255, 255, 0.45);
text-align: center;
font-feature-settings: "liga" off, "clig" off;
font-family: "PingFang SC";
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 20px; /* 166.667% */
}
&-role {
color: #fff;
text-align: center;
font-feature-settings: "liga" off, "clig" off;
font-family: "PingFang SC";
font-size: 12px;
font-style: normal;
font-weight: 500;
line-height: 20px; /* 166.667% */
}
}
}
}
}
}

View File

@@ -0,0 +1,106 @@
import { View, Text, Image, ScrollView } from "@tarojs/components";
import dayjs from "dayjs";
import img from "@/config/images";
import styles from "./index.module.scss";
// 参与者
export default function Participants(props) {
const { detail = {}, handleJoinGame, handleViewUserInfo } = props;
const participants = detail.participants || [];
const {
participant_count,
max_participants,
user_action_status = {},
start_time,
} = detail;
const { can_join, can_pay, can_substitute, is_substituting, waiting_start } =
user_action_status;
const showApplicationEntry =
[can_pay, can_substitute, is_substituting, waiting_start].every(
(item) => !item
) &&
can_join &&
dayjs(start_time).isAfter(dayjs());
const leftCount = max_participants - participant_count;
return (
<View className={styles["detail-page-content-participants"]}>
<View className={styles["participants-title"]}>
<Text></Text>
<Text>·</Text>
<Text>{leftCount > 0 ? `剩余空位 ${leftCount}` : "已满员"}</Text>
</View>
{participant_count > 0 || showApplicationEntry ? (
<View className={styles["participants-list"]}>
{/* application */}
{showApplicationEntry && (
<View
className={styles["participants-list-application"]}
onClick={() => {
handleJoinGame();
}}
>
<Image
className={styles["participants-list-application-icon"]}
src={img.ICON_DETAIL_APPLICATION_ADD}
/>
<Text className={styles["participants-list-application-text"]}>
</Text>
</View>
)}
{/* participants list */}
<ScrollView className={styles["participants-list-scroll"]} scrollX>
<View
className={styles["participants-list-scroll-content"]}
style={{
width: `${
participants.length * 103 + (participants.length - 1) * 8
}px`,
}}
>
{participants.map((participant) => {
const {
is_organizer,
user: {
avatar_url,
nickname,
level,
id: participant_user_id,
},
} = participant;
const role = is_organizer ? "组织者" : "参与者";
return (
<View
key={participant.id}
className={styles["participants-list-item"]}
>
<Image
className={styles["participants-list-item-avatar"]}
mode="aspectFill"
src={avatar_url}
onClick={handleViewUserInfo.bind(
null,
participant_user_id
)}
/>
<Text className={styles["participants-list-item-name"]}>
{nickname || "未知"}
</Text>
<Text className={styles["participants-list-item-level"]}>
{level || "未知"}
</Text>
<Text className={styles["participants-list-item-role"]}>
{role}
</Text>
</View>
);
})}
</View>
</ScrollView>
</View>
) : (
""
)}
</View>
);
}