/**
|
* @author 韩天尊
|
* @time 2024-01-15
|
* @version 1.0.0
|
* @description 管理端活动详情页面组件,包含活动信息、签到二维码和参与人员管理
|
*/
|
import React, { useState, useEffect, useRef } from 'react';
|
import { useNavigate, useParams } from 'react-router-dom';
|
import { useAppContext } from '../context/AppContext';
|
import PageHeader from '../components/PageHeader';
|
import { adminAPI } from '../services/api';
|
import { AdminActivityDetail } from '../types';
|
import QRCode from 'qrcode';
|
import { APP_CONFIG } from '../config/appConfig';
|
|
const AdminActivityDetailPage: React.FC = () => {
|
const navigate = useNavigate();
|
const { id } = useParams<{ id: string }>();
|
const { state } = useAppContext();
|
|
// 状态管理
|
const [activity, setActivity] = useState<AdminActivityDetail | null>(null);
|
const [participants, setParticipants] = useState<any[]>([]);
|
const [showQRCode, setShowQRCode] = useState(false);
|
const [loading, setLoading] = useState(true);
|
const [qrCodeData, setQrCodeData] = useState<any>(null);
|
const [qrCodeUrl, setQrCodeUrl] = useState<string>('');
|
const qrCanvasRef = useRef<HTMLCanvasElement>(null);
|
const [showShareModal, setShowShareModal] = useState(false);
|
|
// 模拟管理端活动数据
|
const adminActivities = [
|
{
|
id: 1,
|
title: '社区清洁日',
|
time: '2024-01-15 09:00',
|
location: '江龙社区广场',
|
content: '组织社区居民进行环境清洁,提升社区环境质量,增强居民环保意识。活动包括道路清扫、垃圾清理、绿化维护等。',
|
status: 'ongoing',
|
category: 'service',
|
maxParticipants: 30,
|
currentParticipants: 18,
|
points: 50,
|
img: 'https://img1.baidu.com/it/u=3535997503,1906944559&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=667'
|
},
|
{
|
id: 2,
|
title: '老年人关爱活动',
|
time: '2024-01-20 14:00',
|
location: '社区养老院',
|
content: '为社区老年人提供关爱服务,包括健康咨询、心理疏导、生活照料等。通过志愿者陪伴,让老年人感受到社会的温暖。',
|
status: 'ongoing',
|
category: 'service',
|
maxParticipants: 20,
|
currentParticipants: 12,
|
points: 80,
|
img: 'https://img1.baidu.com/it/u=3535997503,1906944559&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=667'
|
},
|
{
|
id: 3,
|
title: '环保宣传周',
|
time: '2024-01-25 10:00',
|
location: '社区公园',
|
content: '开展环保知识宣传,提高居民环保意识。通过展板展示、互动游戏、环保讲座等形式,让居民了解环保的重要性。',
|
status: 'upcoming',
|
category: 'service',
|
maxParticipants: 50,
|
currentParticipants: 35,
|
points: 60,
|
img: 'https://img1.baidu.com/it/u=3535997503,1906944559&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=667'
|
},
|
{
|
id: 4,
|
title: '党建知识竞赛',
|
time: '2024-01-30 19:00',
|
location: '社区活动中心',
|
content: '组织党员和积极分子参加党建知识竞赛,深入学习党的理论知识,增强党性修养,提高政治觉悟。',
|
status: 'completed',
|
category: 'party',
|
maxParticipants: 40,
|
currentParticipants: 38,
|
points: 100,
|
img: 'https://img1.baidu.com/it/u=3535997503,1906944559&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=667'
|
},
|
{
|
id: 5,
|
title: '经济发展论坛',
|
time: '2024-02-05 14:00',
|
location: '社区会议室',
|
content: '邀请经济专家和企业家分享经济发展经验,探讨社区经济发展方向,为居民提供创业指导和就业机会。',
|
status: 'completed',
|
category: 'economy',
|
maxParticipants: 60,
|
currentParticipants: 45,
|
points: 120,
|
img: 'https://img1.baidu.com/it/u=3535997503,1906944559&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=667'
|
}
|
];
|
|
// 模拟参与人员数据
|
const mockParticipants = [
|
{
|
id: 1,
|
activityId: 1,
|
name: '张三',
|
phone: '138****1234',
|
location: '江龙社区1号楼',
|
checkinStatus: 'checked',
|
checkinTime: '2024-01-15 08:45'
|
},
|
{
|
id: 2,
|
activityId: 1,
|
name: '李四',
|
phone: '139****5678',
|
location: '江龙社区2号楼',
|
checkinStatus: 'checked',
|
checkinTime: '2024-01-15 08:50'
|
},
|
{
|
id: 3,
|
activityId: 1,
|
name: '王五',
|
phone: '137****9012',
|
location: '江龙社区3号楼',
|
checkinStatus: 'unchecked',
|
checkinTime: null
|
},
|
{
|
id: 4,
|
activityId: 1,
|
name: '赵六',
|
phone: '136****3456',
|
location: '江龙社区4号楼',
|
checkinStatus: 'checked',
|
checkinTime: '2024-01-15 09:00'
|
}
|
];
|
|
// 获取活动详情数据
|
const fetchActivityDetail = async () => {
|
if (!id) return;
|
|
try {
|
setLoading(true);
|
const response = await adminAPI.getActivityDetail(parseInt(id));
|
|
if (response.code === 0) {
|
setActivity(response.data);
|
setParticipants(response.data.participants || []);
|
} else {
|
// API调用失败时使用模拟数据
|
const mockActivity = adminActivities.find(a => a.id === parseInt(id));
|
if (mockActivity) {
|
const activityDetail = {
|
...mockActivity,
|
startTime: mockActivity.time,
|
endTime: mockActivity.time,
|
participants: mockParticipants.map(p => ({
|
id: p.id,
|
userName: p.name,
|
userPhone: p.phone,
|
status: p.checkinStatus === 'checked' ? '2' : '1',
|
checkinLocation: p.location,
|
checkoutLocation: '',
|
checkinTime: p.checkinTime || undefined,
|
checkoutTime: undefined,
|
serviceHours: undefined
|
})),
|
categoryDesc: '民生服务',
|
deadline: mockActivity.time
|
};
|
setActivity(activityDetail);
|
setParticipants(mockParticipants);
|
} else {
|
navigate('/admin-activity-list');
|
}
|
}
|
} catch (error) {
|
console.error('获取活动详情失败:', error);
|
// API调用失败时使用模拟数据
|
const mockActivity = adminActivities.find(a => a.id === parseInt(id));
|
if (mockActivity) {
|
const activityDetail = {
|
...mockActivity,
|
startTime: mockActivity.time,
|
endTime: mockActivity.time,
|
participants: mockParticipants.map(p => ({
|
id: p.id,
|
userName: p.name,
|
userPhone: p.phone,
|
status: p.checkinStatus === 'checked' ? '2' : '1',
|
checkinLocation: p.location,
|
checkoutLocation: '',
|
checkinTime: p.checkinTime || undefined,
|
checkoutTime: undefined,
|
serviceHours: undefined
|
})),
|
categoryDesc: '民生服务',
|
deadline: mockActivity.time
|
};
|
setActivity(activityDetail);
|
setParticipants(mockParticipants);
|
} else {
|
navigate('/admin-activity-list');
|
}
|
} finally {
|
setLoading(false);
|
}
|
};
|
|
// 页面加载完成后初始化
|
useEffect(() => {
|
fetchActivityDetail();
|
}, [id]);
|
|
// 展示签到二维码
|
const handleShowCheckinQR = async () => {
|
if (!id) return;
|
|
try {
|
// 生成签到页面链接
|
const checkinUrl = `${APP_CONFIG.ADMIN_BASE_URL}/#/scan-checkin?activityId=${id}`;
|
|
// 生成二维码并保存为Data URL
|
const qrUrl = await QRCode.toDataURL(checkinUrl, {
|
width: 300,
|
margin: 2,
|
color: {
|
dark: '#000000', // 使用黑色确保扫描识别
|
light: '#FFFFFF'
|
},
|
errorCorrectionLevel: 'H' // 使用高纠错级别
|
});
|
|
setQrCodeUrl(qrUrl);
|
setQrCodeData({ url: checkinUrl, title: activity?.title || '活动签到' });
|
setShowQRCode(true);
|
|
// 延迟生成Canvas版本,确保弹窗已显示
|
setTimeout(async () => {
|
if (qrCanvasRef.current) {
|
console.log('开始生成Canvas二维码');
|
// 设置canvas尺寸
|
qrCanvasRef.current.width = 250;
|
qrCanvasRef.current.height = 250;
|
|
// 清空canvas并设置白色背景
|
const ctx = qrCanvasRef.current.getContext('2d');
|
if (ctx) {
|
ctx.clearRect(0, 0, qrCanvasRef.current.width, qrCanvasRef.current.height);
|
ctx.fillStyle = '#FFFFFF';
|
ctx.fillRect(0, 0, qrCanvasRef.current.width, qrCanvasRef.current.height);
|
}
|
|
try {
|
await QRCode.toCanvas(qrCanvasRef.current, checkinUrl, {
|
width: 250,
|
margin: 2,
|
color: {
|
dark: '#000000',
|
light: '#FFFFFF'
|
},
|
errorCorrectionLevel: 'H'
|
});
|
console.log('Canvas二维码生成成功');
|
} catch (error) {
|
console.error('Canvas二维码生成失败:', error);
|
}
|
} else {
|
console.error('Canvas引用不存在');
|
}
|
}, 100);
|
} catch (error) {
|
console.error('生成二维码失败:', error);
|
alert('生成二维码失败,请重试');
|
}
|
};
|
|
// 关闭签到二维码
|
const handleCloseQR = () => {
|
setShowQRCode(false);
|
};
|
|
// 显示分享弹窗
|
const handleShowShare = () => {
|
setShowShareModal(true);
|
};
|
|
// 关闭分享弹窗
|
const handleCloseShare = () => {
|
setShowShareModal(false);
|
};
|
|
// 生成分享文本
|
const generateShareText = () => {
|
if (!activity || !id) return '';
|
|
const title = activity.title || '活动详情';
|
const activityTime = formatActivityTime(activity.startTime || '', activity.endTime || '');
|
const deadline = activity.deadline ? formatDateTime(activity.deadline) : '';
|
const location = activity.location || '';
|
const signupUrl = `http://lhspfw.haikou.gov.cn/reliefVol/#/activity-detail/${id}`;
|
|
let text = `活动标题:${title}\n`;
|
text += `活动时间:${activityTime}\n`;
|
if (deadline) {
|
text += `报名截止时间:${deadline}\n`;
|
}
|
text += `报名地址:${signupUrl}\n`;
|
text += `活动地址:${location}`;
|
|
return text;
|
};
|
|
// 复制分享文本
|
const handleCopyShareText = async () => {
|
const shareText = generateShareText();
|
|
try {
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
await navigator.clipboard.writeText(shareText);
|
alert('复制成功!');
|
} else {
|
// 兼容旧浏览器
|
const textArea = document.createElement('textarea');
|
textArea.value = shareText;
|
textArea.style.position = 'fixed';
|
textArea.style.left = '-999999px';
|
document.body.appendChild(textArea);
|
textArea.select();
|
const success = document.execCommand('copy');
|
document.body.removeChild(textArea);
|
|
if (success) {
|
alert('复制成功!');
|
} else {
|
alert('复制失败,请手动复制');
|
}
|
}
|
} catch (error) {
|
console.error('复制失败:', error);
|
alert('复制失败,请手动复制');
|
}
|
};
|
|
// 格式化时间为 yyyy-MM-dd HH:mm 格式
|
const formatDateTime = (dateTime: string) => {
|
if (!dateTime) return '';
|
const date = new Date(dateTime);
|
const year = date.getFullYear();
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
const day = String(date.getDate()).padStart(2, '0');
|
const hours = String(date.getHours()).padStart(2, '0');
|
const minutes = String(date.getMinutes()).padStart(2, '0');
|
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
};
|
|
// 构建完整的图片URL
|
const buildImageUrl = (filePath: string) => {
|
// 如果已经是完整URL,直接返回
|
if (filePath.startsWith('http')) {
|
return filePath;
|
}
|
// 否则拼接基础路径
|
return `${APP_CONFIG.API.SYS_BASE_URL}${filePath}`;
|
};
|
|
// 格式化活动时间,根据是否同一天决定显示格式
|
const formatActivityTime = (startTime: string, endTime: string) => {
|
if (!startTime || !endTime) return '';
|
|
const startDate = new Date(startTime);
|
const endDate = new Date(endTime);
|
|
const startYear = startDate.getFullYear();
|
const startMonth = String(startDate.getMonth() + 1).padStart(2, '0');
|
const startDay = String(startDate.getDate()).padStart(2, '0');
|
const startHours = String(startDate.getHours()).padStart(2, '0');
|
const startMinutes = String(startDate.getMinutes()).padStart(2, '0');
|
|
const endYear = endDate.getFullYear();
|
const endMonth = String(endDate.getMonth() + 1).padStart(2, '0');
|
const endDay = String(endDate.getDate()).padStart(2, '0');
|
const endHours = String(endDate.getHours()).padStart(2, '0');
|
const endMinutes = String(endDate.getMinutes()).padStart(2, '0');
|
|
// 判断是否为同一天
|
const isSameDay = startYear === endYear &&
|
startMonth === endMonth &&
|
startDay === endDay;
|
|
if (isSameDay) {
|
// 同一天:yyyy-MM-dd HH:mm - HH:mm
|
return `${startYear}-${startMonth}-${startDay} ${startHours}:${startMinutes} - ${endHours}:${endMinutes}`;
|
} else {
|
// 不同天:yyyy-MM-dd HH:mm - yyyy-MM-dd HH:mm
|
return `${startYear}-${startMonth}-${startDay} ${startHours}:${startMinutes} - ${endYear}-${endMonth}-${endDay} ${endHours}:${endMinutes}`;
|
}
|
};
|
|
// 下载二维码
|
const handleDownloadQR = async () => {
|
if (!qrCodeUrl || !activity || !qrCanvasRef.current) return;
|
|
try {
|
// 创建一个新的Canvas来绘制包含活动信息的二维码
|
const downloadCanvas = document.createElement('canvas');
|
const ctx = downloadCanvas.getContext('2d');
|
if (!ctx) return;
|
|
// 设置Canvas尺寸(比原二维码大一些,留出信息区域)
|
const qrSize = 250;
|
const padding = 20;
|
const infoHeight = 80;
|
downloadCanvas.width = qrSize + (padding * 2);
|
downloadCanvas.height = qrSize + (padding * 2) + infoHeight;
|
|
// 设置白色背景
|
ctx.fillStyle = '#FFFFFF';
|
ctx.fillRect(0, 0, downloadCanvas.width, downloadCanvas.height);
|
|
// 绘制二维码
|
ctx.drawImage(qrCanvasRef.current, padding, padding, qrSize, qrSize);
|
|
// 设置文字样式
|
ctx.fillStyle = '#333333';
|
ctx.font = 'bold 16px Arial, sans-serif';
|
ctx.textAlign = 'center';
|
|
// 绘制活动标题
|
const title = activity.title || '活动签到';
|
ctx.fillText(title, downloadCanvas.width / 2, qrSize + padding + 25);
|
|
// 设置较小字体绘制活动信息
|
ctx.font = '14px Arial, sans-serif';
|
ctx.fillStyle = '#666666';
|
|
// 绘制活动时间
|
const timeText = `活动时间:${formatActivityTime(activity.startTime || '', activity.endTime || '')}`;
|
ctx.fillText(timeText, downloadCanvas.width / 2, qrSize + padding + 45);
|
|
// 绘制活动地点
|
const locationText = `活动地点:${activity.location || ''}`;
|
ctx.fillText(locationText, downloadCanvas.width / 2, qrSize + padding + 65);
|
|
// 转换为Blob并下载
|
downloadCanvas.toBlob((blob) => {
|
if (blob) {
|
const url = URL.createObjectURL(blob);
|
const link = document.createElement('a');
|
link.href = url;
|
link.download = `${title}-签到二维码.png`;
|
document.body.appendChild(link);
|
link.click();
|
document.body.removeChild(link);
|
URL.revokeObjectURL(url);
|
alert('二维码下载成功!');
|
}
|
}, 'image/png');
|
} catch (error) {
|
console.error('下载二维码失败:', error);
|
alert('下载失败,请重试');
|
}
|
};
|
|
|
|
// 剔除参与人员
|
const handleRemoveParticipant = (participantId: number) => {
|
if (window.confirm('确定要剔除该参与人员吗?此操作不可撤销。')) {
|
const updatedParticipants = participants.filter(p => p.id !== participantId);
|
setParticipants(updatedParticipants);
|
alert('已剔除该参与人员');
|
}
|
};
|
|
// 返回上一页
|
const handleGoBack = () => {
|
navigate('/admin-activity-list');
|
};
|
|
// 如果活动数据还未加载,显示加载状态
|
if (!activity) {
|
return (
|
<div className="page admin-activity-detail-page">
|
<PageHeader
|
title="活动详情"
|
onBack={handleGoBack}
|
/>
|
<div className="loading">加载中...</div>
|
</div>
|
);
|
}
|
|
return (
|
<div className="page admin-activity-detail-page">
|
{/* 页面头部 */}
|
<PageHeader
|
title="活动详情"
|
onBack={handleGoBack}
|
/>
|
|
<div className="activity-detail-content">
|
{/* 活动封面 */}
|
<div className="activity-cover">
|
<img
|
src={
|
// 优先显示fileList中的第一张图片
|
activity.fileList && activity.fileList.length > 0
|
? buildImageUrl(activity.fileList[0])
|
: activity.img || require('../image/image1.jpg')
|
}
|
alt="活动封面"
|
id="admin-activity-detail-cover"
|
/>
|
</div>
|
|
{/* 基础信息 */}
|
<div className="detail-section">
|
<h3 className="section-title">基础信息</h3>
|
<div className="detail-info">
|
<div className="detail-item">
|
<label>活动名称</label>
|
<span id="admin-activity-detail-title">{activity.title}</span>
|
</div>
|
<div className="detail-item">
|
<label>活动时间</label>
|
<span id="admin-activity-detail-time">{formatActivityTime(activity.startTime, activity.endTime)}</span>
|
</div>
|
<div className="detail-item">
|
<label>活动地点</label>
|
<span id="admin-activity-detail-location">{activity.location}</span>
|
</div>
|
<div className="detail-item">
|
<label>活动内容</label>
|
<p id="admin-activity-detail-content">{activity.content}</p>
|
</div>
|
<div className="detail-item">
|
<label>报名人数</label>
|
<span>{activity.currentParticipants}/{activity.maxParticipants}人</span>
|
</div>
|
<div className="detail-item">
|
<label>活动积分</label>
|
<span className="activity-points">{activity.points}分</span>
|
</div>
|
</div>
|
</div>
|
|
{/* 签到二维码按钮和分享按钮 */}
|
<div className="action-buttons-section">
|
{(activity.status === 'ongoing' || activity.status === 'upcoming' || activity.status === '1' || activity.status === '2') && (
|
<div className="checkin-qr-section" id="checkin-qr-section">
|
<button className="checkin-qr-btn" onClick={handleShowCheckinQR}>
|
<i className="fas fa-qrcode"></i>
|
<span>签到/签退二维码</span>
|
</button>
|
</div>
|
)}
|
<div className="share-section">
|
<button className="share-btn" onClick={handleShowShare}>
|
<i className="fas fa-share-alt"></i>
|
<span>分享活动</span>
|
</button>
|
</div>
|
</div>
|
|
{/* 参与人员 */}
|
<div className="detail-section">
|
<h3 className="section-title">参与人员</h3>
|
<div className="participants-list">
|
{participants.length > 0 ? (
|
participants.map((participant) => {
|
// 根据status获取状态文本和样式
|
const getStatusInfo = (status: string) => {
|
switch (status) {
|
case '1':
|
return { text: '已报名', className: 'status-registered' };
|
case '2':
|
return { text: '已签到', className: 'status-checked-in' };
|
case '3':
|
return { text: '已签退', className: 'status-checked-out' };
|
default:
|
return { text: '未知状态', className: 'status-unknown' };
|
}
|
};
|
|
const statusInfo = getStatusInfo(participant.status);
|
|
return (
|
<div key={participant.id} className="participant-item">
|
<div className="participant-info">
|
<div className="participant-header">
|
<div className="participant-name">{participant.userName}</div>
|
<div className={`participant-status ${statusInfo.className}`}>
|
{statusInfo.text}
|
</div>
|
</div>
|
<div className="participant-details">
|
<div className="participant-phone">
|
<i className="fas fa-phone"></i>
|
<span>{participant.userPhone}</span>
|
</div>
|
{/* 当status=1时,不展示定位状态 */}
|
{participant.status !== '1' && (
|
<>
|
{participant.checkinLocation && (
|
<div className="participant-location">
|
<i className="fas fa-map-marker-alt"></i>
|
<span>签到地点:{participant.checkinLocation}</span>
|
</div>
|
)}
|
{participant.checkoutLocation && (
|
<div className="participant-location">
|
<i className="fas fa-map-marker-alt"></i>
|
<span>签退地点:{participant.checkoutLocation}</span>
|
</div>
|
)}
|
</>
|
)}
|
{participant.checkinTime && (
|
<div className="checkin-time">
|
<i className="fas fa-clock"></i>
|
<span>签到时间:{formatDateTime(participant.checkinTime)}</span>
|
</div>
|
)}
|
{participant.checkoutTime && (
|
<div className="checkout-time">
|
<i className="fas fa-clock"></i>
|
<span>签退时间:{formatDateTime(participant.checkoutTime)}</span>
|
</div>
|
)}
|
</div>
|
</div>
|
{/* 当status=2或status=3时,不显示剔除按钮 */}
|
{participant.status !== '2' && participant.status !== '3' && (
|
<div className="participant-actions">
|
<button
|
className="remove-btn"
|
onClick={() => handleRemoveParticipant(participant.id)}
|
>
|
<i className="fas fa-user-times"></i>
|
<span>剔除</span>
|
</button>
|
</div>
|
)}
|
</div>
|
);
|
})
|
) : (
|
<div className="no-data">
|
<i className="fas fa-users"></i>
|
<p>暂无参与人员</p>
|
</div>
|
)}
|
</div>
|
</div>
|
</div>
|
|
{/* 签到二维码弹窗 */}
|
{showQRCode && (
|
<div className="qr-modal-overlay" onClick={handleCloseQR}>
|
<div className="qr-modal" onClick={(e) => e.stopPropagation()}>
|
<div className="qr-modal-content">
|
<div className="qr-code-container">
|
{qrCodeUrl ? (
|
<div className="qr-display">
|
<div className="qr-code-border">
|
<canvas ref={qrCanvasRef} className="qr-canvas"></canvas>
|
</div>
|
</div>
|
) : (
|
<div className="qr-loading">
|
<div className="qr-icon">
|
<i className="fas fa-qrcode"></i>
|
</div>
|
<div className="qr-text">
|
<h4>生成二维码中...</h4>
|
<p>请稍候</p>
|
</div>
|
</div>
|
)}
|
</div>
|
<div className="qr-activity-info">
|
<div className="qr-info-item">
|
<i className="fas fa-calendar-alt"></i>
|
<span>活动时间:{formatActivityTime(activity?.startTime || '', activity?.endTime || '')}</span>
|
</div>
|
<div className="qr-info-item">
|
<i className="fas fa-map-marker-alt"></i>
|
<span>活动地点:{activity?.location || ''}</span>
|
</div>
|
</div>
|
<div className="qr-modal-actions">
|
<button className="download-qr-btn" onClick={handleDownloadQR}>
|
<i className="fas fa-download"></i>
|
<span>下载二维码</span>
|
</button>
|
</div>
|
</div>
|
</div>
|
</div>
|
)}
|
|
{/* 分享弹窗 */}
|
{showShareModal && (
|
<div className="share-modal-overlay" onClick={handleCloseShare}>
|
<div className="share-modal" onClick={(e) => e.stopPropagation()}>
|
<div className="share-modal-header">
|
<h3>分享活动</h3>
|
<button className="close-share-modal-btn" onClick={handleCloseShare}>
|
<i className="fas fa-times"></i>
|
</button>
|
</div>
|
<div className="share-modal-content">
|
<div className="share-text-content">
|
<pre>{generateShareText()}</pre>
|
</div>
|
</div>
|
<div className="share-modal-actions">
|
<button className="copy-share-btn" onClick={handleCopyShareText}>
|
<i className="fas fa-copy"></i>
|
<span>复制</span>
|
</button>
|
</div>
|
</div>
|
</div>
|
)}
|
</div>
|
);
|
};
|
|
export default AdminActivityDetailPage;
|