feat: 更新会议管理逻辑和界面

- 重构 `Meetings.tsx` 中的 `canManageRealtimeMeeting` 为 `canManageMeeting`,并更新相关调用
- 在会议卡片中添加创建人信息,并优化会议时间显示
- 增加权限检查,确保只有会议创建人或管理员可以编辑参会人
dev_na
chenhao 2026-04-24 17:30:26 +08:00
parent e6580beaa8
commit 5aefcf8d7d
1 changed files with 22 additions and 4 deletions

View File

@ -84,7 +84,7 @@ const shouldPollMeetingCard = (item: MeetingVO) =>
|| item.realtimeSessionStatus === 'ACTIVE' || item.realtimeSessionStatus === 'ACTIVE'
|| isPausedRealtimeSessionStatus(item.realtimeSessionStatus); || isPausedRealtimeSessionStatus(item.realtimeSessionStatus);
const canManageRealtimeMeeting = (meeting: MeetingVO) => { const canManageMeeting = (meeting: MeetingVO) => {
try { try {
const profileStr = sessionStorage.getItem('userProfile'); const profileStr = sessionStorage.getItem('userProfile');
if (!profileStr) { if (!profileStr) {
@ -97,6 +97,8 @@ const canManageRealtimeMeeting = (meeting: MeetingVO) => {
} }
}; };
const canManageRealtimeMeeting = (meeting: MeetingVO) => canManageMeeting(meeting);
const applyRealtimeSessionStatus = (item: MeetingVO, sessionStatus?: RealtimeMeetingSessionStatus): MeetingVO => { const applyRealtimeSessionStatus = (item: MeetingVO, sessionStatus?: RealtimeMeetingSessionStatus): MeetingVO => {
if (!sessionStatus) { if (!sessionStatus) {
return item; return item;
@ -203,6 +205,7 @@ const MeetingCardItem: React.FC<{ item: MeetingVO, config: any, fetchData: () =>
<Card hoverable onClick={() => onOpenMeeting(item)} className="meeting-card" style={{ borderRadius: 16, border: '1px solid var(--app-border-color)', background: 'var(--app-bg-card)', backdropFilter: 'blur(16px)', height: '220px', position: 'relative', boxShadow: 'var(--app-shadow)', transition: 'all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1)' }} styles={{ body: { padding: 0, display: 'flex', flexDirection: 'row', height: '100%' } }}> <Card hoverable onClick={() => onOpenMeeting(item)} className="meeting-card" style={{ borderRadius: 16, border: '1px solid var(--app-border-color)', background: 'var(--app-bg-card)', backdropFilter: 'blur(16px)', height: '220px', position: 'relative', boxShadow: 'var(--app-shadow)', transition: 'all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1)' }} styles={{ body: { padding: 0, display: 'flex', flexDirection: 'row', height: '100%' } }}>
<div className={isProcessing ? 'status-bar-active' : ''} style={{ width: 6, height: '100%', backgroundColor: config.color, borderRadius: '16px 0 0 16px', flexShrink: 0 }}></div> <div className={isProcessing ? 'status-bar-active' : ''} style={{ width: 6, height: '100%', backgroundColor: config.color, borderRadius: '16px 0 0 16px', flexShrink: 0 }}></div>
<div style={{ flex: 1, padding: '20px 24px', position: 'relative', display: 'flex', flexDirection: 'column', minWidth: 0 }}> <div style={{ flex: 1, padding: '20px 24px', position: 'relative', display: 'flex', flexDirection: 'column', minWidth: 0 }}>
{canManageMeeting(item) && (
<div className="card-actions" style={{ position: 'absolute', top: 16, right: 16, zIndex: 10, background: 'var(--app-bg-card)', borderRadius: 8, padding: '4px' }} onClick={e => e.stopPropagation()}> <div className="card-actions" style={{ position: 'absolute', top: 16, right: 16, zIndex: 10, background: 'var(--app-bg-card)', borderRadius: 8, padding: '4px' }} onClick={e => e.stopPropagation()}>
<Space size={8}> <Space size={8}>
<Tooltip title="编辑参会人"><div className="icon-btn edit"><EditOutlined onClick={() => onEditParticipants(item)} /></div></Tooltip> <Tooltip title="编辑参会人"><div className="icon-btn edit"><EditOutlined onClick={() => onEditParticipants(item)} /></div></Tooltip>
@ -217,6 +220,7 @@ const MeetingCardItem: React.FC<{ item: MeetingVO, config: any, fetchData: () =>
</Popconfirm> </Popconfirm>
</Space> </Space>
</div> </div>
)}
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0 }}> <div style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0 }}>
<div style={{ marginBottom: 12, paddingRight: 80 }}> <div style={{ marginBottom: 12, paddingRight: 80 }}>
@ -226,7 +230,10 @@ const MeetingCardItem: React.FC<{ item: MeetingVO, config: any, fetchData: () =>
<Text strong style={{ fontSize: 16, color: '#262626', lineHeight: '22px' }} ellipsis={{ tooltip: item.title }}>{item.title}</Text> <Text strong style={{ fontSize: 16, color: '#262626', lineHeight: '22px' }} ellipsis={{ tooltip: item.title }}>{item.title}</Text>
</div> </div>
<Space direction="vertical" size={10} style={{ width: '100%', minWidth: 0 }}> <Space direction="vertical" size={10} style={{ width: '100%', minWidth: 0 }}>
<div style={{ fontSize: '13px', color: '#8c8c8c', display: 'flex', alignItems: 'center' }}><CalendarOutlined style={{ marginRight: 10, flexShrink: 0 }} /><span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{dayjs(item.meetingTime).format('YYYY-MM-DD HH:mm')}</span></div> <div style={{ fontSize: '13px', color: '#8c8c8c', display: 'flex', alignItems: 'center', gap: 16 }}>
<div style={{ display: 'flex', alignItems: 'center', minWidth: 0, flexShrink: 1 }}><CalendarOutlined style={{ marginRight: 6, flexShrink: 0 }} /><span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{dayjs(item.meetingTime).format('YYYY-MM-DD HH:mm')}</span></div>
<div style={{ display: 'flex', alignItems: 'center', minWidth: 0, flexShrink: 1 }}><UserOutlined style={{ marginRight: 6, flexShrink: 0 }} /><span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{item.creatorName || '未知'}</span></div>
</div>
{isProcessing ? ( {isProcessing ? (
<div style={{ <div style={{
fontSize: '12px', fontSize: '12px',
@ -455,6 +462,10 @@ const Meetings: React.FC = () => {
}; };
const openEditParticipants = (meeting: MeetingVO) => { const openEditParticipants = (meeting: MeetingVO) => {
if (!canManageMeeting(meeting)) {
message.warning('只有会议创建人或管理员可以修改参会人');
return;
}
setEditingMeeting(meeting); setEditingMeeting(meeting);
participantsEditForm.setFieldsValue({ participantsEditForm.setFieldsValue({
participantIds: meeting.participantIds || [] participantIds: meeting.participantIds || []
@ -517,6 +528,13 @@ const Meetings: React.FC = () => {
width: 180, width: 180,
render: (text: string) => dayjs(text).format('YYYY-MM-DD HH:mm') render: (text: string) => dayjs(text).format('YYYY-MM-DD HH:mm')
}, },
{
title: '创建人',
dataIndex: 'creatorName',
key: 'creatorName',
width: 120,
render: (text: string) => <Text type="secondary" ellipsis>{text || '未知'}</Text>
},
{ {
title: '参会人', title: '参会人',
dataIndex: 'participants', dataIndex: 'participants',
@ -529,7 +547,7 @@ const Meetings: React.FC = () => {
title: '操作', title: '操作',
key: 'action', key: 'action',
width: 160, width: 160,
render: (_: any, record: MeetingVO) => ( render: (_: any, record: MeetingVO) => canManageMeeting(record) ? (
<Space size="middle"> <Space size="middle">
<Button type="link" size="small" onClick={(e) => { e.stopPropagation(); openEditParticipants(record); }}></Button> <Button type="link" size="small" onClick={(e) => { e.stopPropagation(); openEditParticipants(record); }}></Button>
<Popconfirm <Popconfirm
@ -542,7 +560,7 @@ const Meetings: React.FC = () => {
<Button type="link" danger size="small" onClick={(e) => e.stopPropagation()}></Button> <Button type="link" danger size="small" onClick={(e) => e.stopPropagation()}></Button>
</Popconfirm> </Popconfirm>
</Space> </Space>
) ) : <Text type="secondary">-</Text>
} }
]; ];