import React, { useState, useEffect, useRef } from 'react';
import { LogOut, User, Calendar, Users, TrendingUp, Clock, MessageSquare, Plus, ChevronDown, KeyRound, Shield, Filter, X, Library, BookText, Waves } from 'lucide-react';
import apiClient from '../utils/apiClient';
import { Link } from 'react-router-dom';
import { buildApiUrl, API_ENDPOINTS } from '../config/api';
import MeetingTimeline from '../components/MeetingTimeline';
import TagCloud from '../components/TagCloud';
import VoiceprintCollectionModal from '../components/VoiceprintCollectionModal';
import ConfirmDialog from '../components/ConfirmDialog';
import PageLoading from '../components/PageLoading';
import './Dashboard.css';
const Dashboard = ({ user, onLogout }) => {
const [userInfo, setUserInfo] = useState(null);
const [meetings, setMeetings] = useState(null);
const [filteredMeetings, setFilteredMeetings] = useState([]);
const [selectedTags, setSelectedTags] = useState([]);
const [filterType, setFilterType] = useState('all'); // 'all', 'created', 'attended'
const [loading, setLoading] = useState(true);
const [error, setError] = useState('');
const [dropdownOpen, setDropdownOpen] = useState(false);
const [showChangePasswordModal, setShowChangePasswordModal] = useState(false);
const [oldPassword, setOldPassword] = useState('');
const [newPassword, setNewPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [passwordChangeError, setPasswordChangeError] = useState('');
const [passwordChangeSuccess, setPasswordChangeSuccess] = useState('');
const dropdownRef = useRef(null);
// 声纹相关状态
const [voiceprintStatus, setVoiceprintStatus] = useState(null);
const [showVoiceprintModal, setShowVoiceprintModal] = useState(false);
const [voiceprintTemplate, setVoiceprintTemplate] = useState(null);
const [voiceprintLoading, setVoiceprintLoading] = useState(true);
const [showDeleteVoiceprintDialog, setShowDeleteVoiceprintDialog] = useState(false);
useEffect(() => {
fetchUserData();
fetchVoiceprintData();
}, [user.user_id]);
const fetchVoiceprintData = async () => {
try {
setVoiceprintLoading(true);
// 获取声纹状态
const statusResponse = await apiClient.get(buildApiUrl(API_ENDPOINTS.VOICEPRINT.STATUS(user.user_id)));
console.log('声纹状态响应:', statusResponse);
setVoiceprintStatus(statusResponse.data);
// 获取朗读模板
const templateResponse = await apiClient.get(buildApiUrl(API_ENDPOINTS.VOICEPRINT.TEMPLATE));
console.log('朗读模板响应:', templateResponse);
setVoiceprintTemplate(templateResponse.data);
} catch (err) {
console.error('获取声纹数据失败:', err);
} finally {
setVoiceprintLoading(false);
}
};
// 过滤会议
useEffect(() => {
filterMeetings();
}, [meetings, selectedTags, filterType]);
const filterMeetings = () => {
if (!meetings) return;
let filtered = [...meetings];
// 根据创建/参与类型过滤
if (filterType === 'created') {
filtered = filtered.filter(meeting => String(meeting.creator_id) === String(user.user_id));
} else if (filterType === 'attended') {
filtered = filtered.filter(meeting => String(meeting.creator_id) !== String(user.user_id));
}
// 根据选中的标签过滤
if (selectedTags.length > 0) {
filtered = filtered.filter(meeting => {
if (!meeting.tags || meeting.tags.length === 0) return false;
const meetingTags = meeting.tags.map(tag => typeof tag === 'string' ? tag : tag.name);
return selectedTags.some(selectedTag => meetingTags.includes(selectedTag));
});
}
setFilteredMeetings(filtered);
};
const handleTagClick = (tagName) => {
setSelectedTags(prev => {
if (prev.includes(tagName)) {
return prev.filter(tag => tag !== tagName);
} else {
return [...prev, tagName];
}
});
};
const handleFilterTypeChange = (type) => {
setFilterType(type);
};
const clearFilters = () => {
setSelectedTags([]);
setFilterType('all');
};
useEffect(() => {
const handleClickOutside = (event) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
setDropdownOpen(false);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [dropdownRef]);
const fetchUserData = async () => {
try {
setLoading(true);
console.log('Fetching user data for user_id:', user.user_id);
const userResponse = await apiClient.get(buildApiUrl(API_ENDPOINTS.USERS.DETAIL(user.user_id)));
console.log('User response:', userResponse.data);
setUserInfo(userResponse.data);
const meetingsResponse = await apiClient.get(buildApiUrl(`${API_ENDPOINTS.MEETINGS.LIST}?user_id=${user.user_id}`));
setMeetings(meetingsResponse.data);
} catch (err) {
console.error('Error fetching data:', err);
setError('获取数据失败,请刷新重试');
} finally {
setLoading(false);
}
};
const handleDeleteMeeting = async (meetingId) => {
try {
await apiClient.delete(buildApiUrl(API_ENDPOINTS.MEETINGS.DELETE(meetingId)));
// Refresh meetings list
const meetingsResponse = await apiClient.get(buildApiUrl(`${API_ENDPOINTS.MEETINGS.LIST}?user_id=${user.user_id}`));
setMeetings(meetingsResponse.data);
} catch (err) {
console.error('Error deleting meeting:', err);
// You might want to show an error message to the user here
}
};
const handlePasswordChange = async (e) => {
e.preventDefault();
if (newPassword !== confirmPassword) {
setPasswordChangeError('新密码不匹配');
return;
}
if (newPassword.length < 6) {
setPasswordChangeError('新密码长度不能少于6位');
return;
}
setPasswordChangeError('');
setPasswordChangeSuccess('');
try {
await apiClient.put(buildApiUrl(API_ENDPOINTS.USERS.UPDATE_PASSWORD(user.user_id)), {
old_password: oldPassword,
new_password: newPassword,
});
setPasswordChangeSuccess('密码修改成功!');
// 清空输入框并准备关闭模态框
setOldPassword('');
setNewPassword('');
setConfirmPassword('');
setTimeout(() => {
setShowChangePasswordModal(false);
setPasswordChangeSuccess('');
}, 2000);
} catch (err) {
setPasswordChangeError(err.response?.data?.message || '密码修改失败');
}
};
const handleVoiceprintUpload = async (formData) => {
try {
await apiClient.post(
buildApiUrl(API_ENDPOINTS.VOICEPRINT.UPLOAD(user.user_id)),
formData,
{
headers: {
'Content-Type': 'multipart/form-data',
},
}
);
// 上传成功后刷新声纹状态并关闭模态框
await fetchVoiceprintData();
setShowVoiceprintModal(false);
} catch (err) {
throw new Error(err.response?.data?.message || '声纹上传失败');
}
};
const handleDeleteVoiceprint = async () => {
try {
await apiClient.delete(buildApiUrl(API_ENDPOINTS.VOICEPRINT.DELETE(user.user_id)));
await fetchVoiceprintData();
} catch (err) {
console.error('删除声纹失败:', err);
}
};
const groupMeetingsByDate = (meetingsToGroup) => {
return meetingsToGroup.reduce((acc, meeting) => {
const date = new Date(meeting.meeting_time || meeting.created_at).toISOString().split('T')[0];
if (!acc[date]) {
acc[date] = [];
}
acc[date].push(meeting);
return acc;
}, {});
};
const formatDate = (dateString) => {
const date = new Date(dateString);
return date.toLocaleDateString('zh-CN', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
};
if (loading || !meetings) {
return
{error}
{userInfo?.email}
加入时间:{formatDate(userInfo?.created_at)}
贯穿内容,生成知识库
按时间顺序展示您参与的所有会议