修正了部分页面显示问题

main
mula.liu 2026-02-11 10:26:50 +08:00
parent e2211fbc9b
commit e6794a1952
6 changed files with 188 additions and 67 deletions

View File

@ -2,6 +2,8 @@ import { useEffect } from 'react'
import { BrowserRouter, Routes, Route, Navigate, useParams, Outlet } from 'react-router-dom' import { BrowserRouter, Routes, Route, Navigate, useParams, Outlet } from 'react-router-dom'
import { ConfigProvider, theme } from 'antd' import { ConfigProvider, theme } from 'antd'
import zhCN from 'antd/locale/zh_CN' import zhCN from 'antd/locale/zh_CN'
import dayjs from 'dayjs'
import 'dayjs/locale/zh-cn'
import useThemeStore from '@/stores/themeStore' import useThemeStore from '@/stores/themeStore'
import Login from '@/pages/Login/Login' import Login from '@/pages/Login/Login'
import ProjectList from '@/pages/ProjectList/ProjectList' import ProjectList from '@/pages/ProjectList/ProjectList'
@ -21,6 +23,8 @@ import ProtectedRoute from '@/components/ProtectedRoute'
import MainLayout from '@/components/MainLayout/MainLayout' import MainLayout from '@/components/MainLayout/MainLayout'
import '@/App.css' import '@/App.css'
dayjs.locale('zh-cn')
// //
function RedirectToDocs() { function RedirectToDocs() {
const { projectId } = useParams() const { projectId } = useParams()

View File

@ -4,20 +4,51 @@
.page-title { .page-title {
margin-bottom: 24px; margin-bottom: 24px;
color: #333;
font-size: 24px; font-size: 24px;
font-weight: 600; font-weight: 600;
} }
/* 日历卡片 */
.calendar-card { .calendar-card {
height: 100%; height: 100%;
min-height: 400px; min-height: 400px;
} }
.calendar-card .ant-picker-calendar { .calendar-card .ant-picker-calendar {
padding: 12px; padding: 0;
} }
/* 日历头部选择器 */
.calendar-card .ant-picker-calendar-header {
padding: 8px 12px;
}
/* 日历单元格 - 迷你模式 */
.calendar-card .ant-picker-cell {
position: relative;
}
.calendar-card .ant-picker-cell .ant-picker-cell-inner {
min-width: 28px;
height: 28px;
line-height: 28px;
border-radius: 6px;
}
/* Badge 相对于日期本身定位 */
.calendar-card .ant-badge {
display: inline-block;
position: relative;
}
.calendar-card .ant-badge-count {
position: absolute;
top: -2px;
right: -2px;
z-index: 10;
}
/* 活动卡片 */
.activity-card { .activity-card {
height: 100%; height: 100%;
min-height: 400px; min-height: 400px;
@ -58,17 +89,17 @@
border-radius: 4px; border-radius: 4px;
} }
/* 日历单元格样式 */ /* 暗色模式适配 */
.ant-picker-calendar-date { body.dark .activity-item-clickable:hover {
position: relative; background-color: rgba(24, 144, 255, 0.15);
} }
.ant-picker-calendar-date-today { body.dark .activity-item-clickable:active {
border-color: #1890ff; background-color: rgba(24, 144, 255, 0.25);
} }
.ant-picker-calendar-date-selected { body.dark .activity-item-disabled:hover {
background-color: #e6f7ff; background-color: rgba(255, 255, 255, 0.04);
} }
/* 响应式调整 */ /* 响应式调整 */

View File

@ -53,22 +53,31 @@ function Desktop() {
} }
// //
const dateCellRender = (value) => { const dateCellRender = (value, info) => {
if (info.type !== 'date') return info.originNode
const dateStr = value.format('YYYY-MM-DD') const dateStr = value.format('YYYY-MM-DD')
const activity = activityDates.find(item => item.date === dateStr) const activity = activityDates.find(item => item.date === dateStr)
if (activity && activity.count > 0) { if (activity && activity.count > 0) {
return ( return (
<div style={{ textAlign: 'center' }}> <Badge
<Badge count={activity.count}
count={activity.count} style={{
style={{ backgroundColor: '#1890ff' }} backgroundColor: '#ff4d4f',
overflowCount={99} fontSize: '10px',
/> height: '16px',
</div> lineHeight: '16px',
minWidth: '16px',
padding: '0 4px'
}}
>
{info.originNode}
</Badge>
) )
} }
return null
return info.originNode
} }
// //
@ -114,7 +123,7 @@ function Desktop() {
value={selectedDate} value={selectedDate}
onSelect={onSelect} onSelect={onSelect}
onPanelChange={onPanelChange} onPanelChange={onPanelChange}
cellRender={dateCellRender} fullCellRender={dateCellRender}
/> />
</Card> </Card>
</Col> </Col>

View File

@ -18,6 +18,7 @@ import {
FilePdfOutlined, FilePdfOutlined,
FileTextOutlined, FileTextOutlined,
UndoOutlined, UndoOutlined,
CloseOutlined,
} from '@ant-design/icons' } from '@ant-design/icons'
import { Editor } from '@bytemd/react' import { Editor } from '@bytemd/react'
import gfm from '@bytemd/plugin-gfm' import gfm from '@bytemd/plugin-gfm'
@ -889,7 +890,11 @@ function DocumentEditor() {
className="document-sider" className="document-sider"
> >
<div className="sider-header"> <div className="sider-header">
<h2>{projectName}</h2> <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
<h2 style={{ margin: 0, flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }} title={projectName}>
{projectName}
</h2>
</div>
<div className="sider-actions"> <div className="sider-actions">
<Space size={8}> <Space size={8}>
<Button <Button

View File

@ -75,3 +75,46 @@
font-size: 12px; font-size: 12px;
color: var(--text-color-secondary); color: var(--text-color-secondary);
} }
/* 圆点分页指示器样式 */
.dot-pagination.ant-pagination {
display: flex;
align-items: center;
}
.dot-pagination .ant-pagination-item {
border: none !important;
background: transparent !important;
min-width: 16px !important;
height: 16px !important;
line-height: 16px !important;
margin: 0 4px !important;
}
.dot-pagination .ant-pagination-item a {
display: none !important;
}
.dot-pagination .pagination-dot {
display: block;
width: 8px;
height: 8px;
border-radius: 50%;
background-color: var(--text-color-secondary);
opacity: 0.3;
margin: 4px auto;
transition: all 0.3s;
}
.dot-pagination .ant-pagination-item-active .pagination-dot {
background-color: var(--link-color);
opacity: 1;
transform: scale(1.2);
}
.dot-pagination .ant-pagination-prev,
.dot-pagination .ant-pagination-next {
min-width: 24px !important;
height: 24px !important;
line-height: 24px !important;
}

View File

@ -1,6 +1,6 @@
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { Card, Empty, Modal, Form, Input, Row, Col, Space, Button, Switch, message, Select, Table, Tag } from 'antd' import { Card, Empty, Modal, Form, Input, Row, Col, Space, Button, Switch, message, Select, Table, Tag, Pagination } from 'antd'
import { PlusOutlined, FolderOutlined, TeamOutlined, EyeOutlined, ShareAltOutlined, CopyOutlined, DeleteOutlined, EditOutlined, FileOutlined, GithubOutlined, CheckOutlined, SwapOutlined } from '@ant-design/icons' import { PlusOutlined, FolderOutlined, TeamOutlined, EyeOutlined, ShareAltOutlined, CopyOutlined, DeleteOutlined, EditOutlined, FileOutlined, GithubOutlined, CheckOutlined, SwapOutlined } from '@ant-design/icons'
import { getMyProjects, getOwnedProjects, getSharedProjects, createProject, deleteProject, updateProject, getProjectMembers, addProjectMember, removeProjectMember, getGitRepos, createGitRepo, updateGitRepo, deleteGitRepo, transferProject } from '@/api/project' import { getMyProjects, getOwnedProjects, getSharedProjects, createProject, deleteProject, updateProject, getProjectMembers, addProjectMember, removeProjectMember, getGitRepos, createGitRepo, updateGitRepo, deleteGitRepo, transferProject } from '@/api/project'
import { getProjectShareInfo, updateShareSettings } from '@/api/share' import { getProjectShareInfo, updateShareSettings } from '@/api/share'
@ -36,11 +36,18 @@ function ProjectList({ type = 'my' }) {
const [transferModalVisible, setTransferModalVisible] = useState(false) const [transferModalVisible, setTransferModalVisible] = useState(false)
const [transferForm] = Form.useForm() const [transferForm] = Form.useForm()
const navigate = useNavigate() const navigate = useNavigate()
const [currentPage, setCurrentPage] = useState(1)
const pageSize = 8
useEffect(() => { useEffect(() => {
fetchProjects() fetchProjects()
setCurrentPage(1)
}, [type]) }, [type])
useEffect(() => {
setCurrentPage(1)
}, [searchKeyword])
// ... (fetchProjects code) // ... (fetchProjects code)
const handleOpenTransfer = async () => { const handleOpenTransfer = async () => {
@ -472,6 +479,8 @@ function ProjectList({ type = 'my' }) {
) )
: projects : projects
const paginatedProjects = filteredProjects.slice((currentPage - 1) * pageSize, currentPage * pageSize)
return ( return (
<div className="project-list-container"> <div className="project-list-container">
<ListActionBar <ListActionBar
@ -545,55 +554,75 @@ function ProjectList({ type = 'my' }) {
{/* 正常项目列表 */} {/* 正常项目列表 */}
{!hasSearched && ( {!hasSearched && (
<Row gutter={[16, 16]} style={{ marginTop: 16 }}> <>
{filteredProjects.map((project) => ( <Row gutter={[16, 16]} style={{ marginTop: 16 }}>
<Col xs={24} sm={12} md={8} lg={6} key={project.id}> {paginatedProjects.map((project) => (
<Card <Col xs={24} sm={12} md={8} lg={6} key={project.id}>
hoverable <Card
className="project-card" hoverable
onClick={() => handleOpenProject(project.id)} className="project-card"
actions={type === 'my' ? [ onClick={() => handleOpenProject(project.id)}
<EditOutlined key="edit" onClick={(e) => handleEdit(e, project)} />, actions={type === 'my' ? [
<GithubOutlined key="git" onClick={(e) => handleGitSettings(e, project)} />, <EditOutlined key="edit" onClick={(e) => handleEdit(e, project)} />,
<ShareAltOutlined key="share" onClick={(e) => handleShare(e, project)} />, <GithubOutlined key="git" onClick={(e) => handleGitSettings(e, project)} />,
<TeamOutlined key="members" onClick={(e) => handleMembers(e, project)} />, <ShareAltOutlined key="share" onClick={(e) => handleShare(e, project)} />,
] : [ <TeamOutlined key="members" onClick={(e) => handleMembers(e, project)} />,
<EyeOutlined key="view" />, ] : [
<ShareAltOutlined key="share" onClick={(e) => handleShare(e, project)} />, <EyeOutlined key="view" />,
]} <ShareAltOutlined key="share" onClick={(e) => handleShare(e, project)} />,
> ]}
{/* 公开项目标识 */} >
{project.is_public === 1 && ( {/* 公开项目标识 */}
<div className="project-card-public-badge">公开</div> {project.is_public === 1 && (
)} <div className="project-card-public-badge">公开</div>
<div className="project-card-icon">
<FolderOutlined style={{ fontSize: 48, color: '#1890ff' }} />
</div>
<h3>{project.name}</h3>
<p className="project-description">{project.description || '暂无描述'}</p>
<div className="project-meta">
<span>文档数: {project.doc_count || 0}</span>
{type === 'share' && project.owner_name && (
<span style={{ marginLeft: 12 }}>
所有者: {project.owner_nickname || project.owner_name}
</span>
)} )}
{type === 'share' && project.user_role && ( <div className="project-card-icon">
<span style={{ marginLeft: 12 }}> <FolderOutlined style={{ fontSize: 48, color: '#1890ff' }} />
角色: {project.user_role === 'admin' ? '管理者' : project.user_role === 'editor' ? '编辑者' : '查看者'} </div>
</span> <h3>{project.name}</h3>
)} <p className="project-description">{project.description || '暂无描述'}</p>
</div> <div className="project-meta">
</Card> <span>文档数: {project.doc_count || 0}</span>
</Col> {type === 'share' && project.owner_name && (
))} <span style={{ marginLeft: 12 }}>
所有者: {project.owner_nickname || project.owner_name}
</span>
)}
{type === 'share' && project.user_role && (
<span style={{ marginLeft: 12 }}>
角色: {project.user_role === 'admin' ? '管理者' : project.user_role === 'editor' ? '编辑者' : '查看者'}
</span>
)}
</div>
</Card>
</Col>
))}
{filteredProjects.length === 0 && !loading && ( {filteredProjects.length === 0 && !loading && (
<Col span={24}> <Col span={24}>
<Empty description={type === 'my' ? "还没有项目,创建一个开始吧" : "还没有参与的项目"} /> <Empty description={type === 'my' ? "还没有项目,创建一个开始吧" : "还没有参与的项目"} />
</Col> </Col>
)}
</Row>
{filteredProjects.length > 0 && (
<div style={{ marginTop: 24, display: 'flex', justifyContent: 'center' }}>
<Pagination
current={currentPage}
pageSize={pageSize}
total={filteredProjects.length}
onChange={setCurrentPage}
showSizeChanger={false}
className="dot-pagination"
itemRender={(page, type, originalElement) => {
if (type === 'page') {
return <span className="pagination-dot" />
}
return originalElement
}}
/>
</div>
)} )}
</Row> </>
)} )}
{/* 搜索无结果提示 */} {/* 搜索无结果提示 */}