nex_docus/frontend/src/pages/Desktop.jsx

203 lines
6.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { useState, useEffect } from 'react'
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'
import Toast from '@/components/Toast/Toast'
import dayjs from 'dayjs'
import './Desktop.css'
const { Text } = Typography
function Desktop() {
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())
useEffect(() => {
loadActivityDates(currentMonth.year(), currentMonth.month() + 1)
loadActivityLogs(selectedDate.format('YYYY-MM-DD'))
}, [])
// 加载指定月份有活动的日期
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)
try {
const res = await getDocumentActivity(date)
if (res.data && res.data.logs) {
setActivityLogs(res.data.logs)
} else {
setActivityLogs([])
}
} catch (error) {
console.error('Load activity logs error:', error)
Toast.error('加载失败', '获取文档活动记录失败')
} finally {
setLoading(false)
}
}
// 日历单元格渲染
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}
/>
</div>
)
}
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}/docs?file=${encodeURIComponent(log.file_path)}`)
}
return (
<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>
)
}
export default Desktop