nex_docus/frontend/src/pages/Desktop.jsx

203 lines
6.6 KiB
React
Raw Normal View History

2025-12-20 11:18:59 +00:00
import { useState, useEffect } from 'react'
2026-01-13 13:21:47 +00:00
import { Card, Row, Col, Calendar, List, Badge, Empty, Typography, Spin } from 'antd'
import { FileTextOutlined, ClockCircleOutlined } from '@ant-design/icons'
import { useNavigate } from 'react-router-dom'
import { getDocumentActivityDates, getDocumentActivity } from '@/api/dashboard'
2025-12-20 11:18:59 +00:00
import Toast from '@/components/Toast/Toast'
2026-01-13 13:21:47 +00:00
import dayjs from 'dayjs'
import './Desktop.css'
const { Text } = Typography
2025-12-20 11:18:59 +00:00
function Desktop() {
2026-01-13 13:21:47 +00:00
const navigate = useNavigate()
const [loading, setLoading] = useState(false)
const [activityDates, setActivityDates] = useState([])
const [selectedDate, setSelectedDate] = useState(dayjs())
const [activityLogs, setActivityLogs] = useState([])
const [currentMonth, setCurrentMonth] = useState(dayjs())
2025-12-20 11:18:59 +00:00
useEffect(() => {
2026-01-13 13:21:47 +00:00
loadActivityDates(currentMonth.year(), currentMonth.month() + 1)
loadActivityLogs(selectedDate.format('YYYY-MM-DD'))
2025-12-20 11:18:59 +00:00
}, [])
2026-01-13 13:21:47 +00:00
// 加载指定月份有活动的日期
const loadActivityDates = async (year, month) => {
try {
const res = await getDocumentActivityDates(year, month)
if (res.data && res.data.dates) {
setActivityDates(res.data.dates)
}
} catch (error) {
console.error('Load activity dates error:', error)
}
}
// 加载指定日期的活动日志
const loadActivityLogs = async (date) => {
setLoading(true)
2025-12-20 11:18:59 +00:00
try {
2026-01-13 13:21:47 +00:00
const res = await getDocumentActivity(date)
if (res.data && res.data.logs) {
setActivityLogs(res.data.logs)
} else {
setActivityLogs([])
2025-12-20 11:18:59 +00:00
}
} catch (error) {
2026-01-13 13:21:47 +00:00
console.error('Load activity logs error:', error)
Toast.error('加载失败', '获取文档活动记录失败')
2025-12-20 11:18:59 +00:00
} finally {
setLoading(false)
}
}
2026-01-13 13:21:47 +00:00
// 日历单元格渲染
const dateCellRender = (value) => {
const dateStr = value.format('YYYY-MM-DD')
const activity = activityDates.find(item => item.date === dateStr)
if (activity && activity.count > 0) {
return (
<div style={{ textAlign: 'center' }}>
<Badge
count={activity.count}
style={{ backgroundColor: '#1890ff' }}
overflowCount={99}
/>
2025-12-20 11:18:59 +00:00
</div>
2026-01-13 13:21:47 +00:00
)
}
return null
}
// 日期选择事件
const onSelect = (date) => {
setSelectedDate(date)
loadActivityLogs(date.format('YYYY-MM-DD'))
}
// 月份切换事件
const onPanelChange = (date) => {
setCurrentMonth(date)
loadActivityDates(date.year(), date.month() + 1)
}
// 点击文档打开
const handleDocumentClick = (log) => {
// 如果文件不存在,提示无法打开
if (!log.file_exists) {
Toast.warning('无法打开', '文件不存在或已被删除/移动/重命名')
return
}
// 如果没有项目ID提示无法打开
if (!log.project_id) {
Toast.error('无法打开', '找不到对应的项目')
return
}
// 跳转到文档页面
navigate(`/projects/${log.project_id}/documents?path=${encodeURIComponent(log.file_path)}`)
2025-12-20 11:18:59 +00:00
}
return (
2026-01-13 13:21:47 +00:00
<div className="desktop-page">
<h1 className="page-title">个人桌面</h1>
<Row gutter={24}>
{/* 左侧日历 */}
<Col xs={24} lg={12}>
<Card className="calendar-card">
<Calendar
fullscreen={false}
value={selectedDate}
onSelect={onSelect}
onPanelChange={onPanelChange}
cellRender={dateCellRender}
/>
</Card>
</Col>
{/* 右侧活动列表 */}
<Col xs={24} lg={12}>
<Card
className="activity-card"
title={
<div>
<FileTextOutlined style={{ marginRight: 8 }} />
{selectedDate.format('YYYY年MM月DD日')} 的文档活动
</div>
}
>
<Spin spinning={loading}>
{activityLogs.length > 0 ? (
<List
dataSource={activityLogs}
renderItem={(item) => (
<List.Item
key={item.id}
onClick={() => handleDocumentClick(item)}
className={item.file_exists ? 'activity-item-clickable' : 'activity-item-disabled'}
style={{ cursor: item.file_exists ? 'pointer' : 'default' }}
>
<List.Item.Meta
avatar={
<ClockCircleOutlined
style={{
fontSize: 20,
color: item.file_exists ? '#1890ff' : '#d9d9d9'
}}
/>
}
title={
<div>
<Text strong style={{ color: item.file_exists ? undefined : '#999' }}>
{item.project_name}
</Text>
<Text
type="secondary"
style={{ marginLeft: 8, color: item.file_exists ? undefined : '#bbb' }}
>
{item.operation_type}
</Text>
{!item.file_exists && (
<Text type="danger" style={{ marginLeft: 8, fontSize: 12 }}>
(已失效)
</Text>
)}
</div>
}
description={
<div>
<div style={{ marginBottom: 4 }}>
<Text type="secondary">文件</Text>
<Text code style={{ color: item.file_exists ? undefined : '#999' }}>
{item.file_path}
</Text>
</div>
<Text type="secondary" style={{ fontSize: 12 }}>
{new Date(item.created_at).toLocaleTimeString('zh-CN')}
</Text>
</div>
}
/>
</List.Item>
)}
/>
) : (
<Empty
image={Empty.PRESENTED_IMAGE_SIMPLE}
description="该日期暂无文档活动记录"
/>
)}
</Spin>
</Card>
</Col>
</Row>
</div>
2025-12-20 11:18:59 +00:00
)
}
export default Desktop