mirror of
https://github.com/lifegpc/bookdownload.git
synced 2026-07-08 01:31:31 +08:00
Add manage page
This commit is contained in:
23
src/manage/Home.tsx
Normal file
23
src/manage/Home.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Breadcrumb, Button, Card, Divider, Space, Typography } from 'antd';
|
||||
import { useNavigate } from 'react-router';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
export default function Home() {
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<>
|
||||
<Breadcrumb items={
|
||||
[{
|
||||
title: '主页'
|
||||
}]
|
||||
} />
|
||||
<Divider />
|
||||
<Space orientation="vertical" size="large">
|
||||
<Card title="起点">
|
||||
<Button type="primary" onClick={() => navigate("/qd/books")}>按书籍管理</Button>
|
||||
</Card>
|
||||
</Space>
|
||||
</>
|
||||
)
|
||||
}
|
||||
8
src/manage/dbProvider.tsx
Normal file
8
src/manage/dbProvider.tsx
Normal file
@@ -0,0 +1,8 @@
|
||||
import { createContext, useContext } from "react";
|
||||
import type { Db } from "../db/interfaces";
|
||||
|
||||
export const DbContext = createContext<Db>(null as any);
|
||||
|
||||
export function useDb() {
|
||||
return useContext(DbContext);
|
||||
}
|
||||
49
src/manage/qd/Book.tsx
Normal file
49
src/manage/qd/Book.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import { Breadcrumb, Result, Button, Skeleton } from "antd";
|
||||
import { NavLink, useParams } from "react-router";
|
||||
import { useDb } from "../dbProvider";
|
||||
import type { QdBookInfo } from "../../types";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export default function Book() {
|
||||
const db = useDb();
|
||||
const { id } = useParams();
|
||||
const [book, setBook] = useState<QdBookInfo | null>(null);
|
||||
const [err, setErr] = useState<string | null>(null);
|
||||
async function load() {
|
||||
const data = await db.getQdBook(Number(id));
|
||||
if (data) {
|
||||
setBook(data);
|
||||
} else {
|
||||
setErr("书籍不存在");
|
||||
}
|
||||
}
|
||||
function handle() {
|
||||
load().catch(e => {
|
||||
setErr(e instanceof Error ? e.message : String(e));
|
||||
});
|
||||
}
|
||||
useEffect(() => {
|
||||
handle();
|
||||
}, [id]);
|
||||
return (
|
||||
<>
|
||||
<Breadcrumb items={
|
||||
[{
|
||||
title: <NavLink to="/">主页</NavLink>
|
||||
}, {
|
||||
title: '起点'
|
||||
}, {
|
||||
title: <NavLink to="/qd/books">按书籍管理</NavLink>
|
||||
}, {
|
||||
title: book ? `书籍详情:${book.bookName}` : '书籍详情'
|
||||
}]
|
||||
} />
|
||||
{!book && !err && <Skeleton active />}
|
||||
{err && <Result
|
||||
status="error"
|
||||
title="数据加载失败"
|
||||
subTitle={err}
|
||||
extra={<Button type="primary" onClick={() => { setErr(null); handle(); }}>重试</Button>} />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
20
src/manage/qd/Books.module.css
Normal file
20
src/manage/qd/Books.module.css
Normal file
@@ -0,0 +1,20 @@
|
||||
.books-card {
|
||||
margin: 8px;
|
||||
max-width: 400px;
|
||||
min-width: 350px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.books-card .name {
|
||||
margin: 0 8px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.books-card .author {
|
||||
margin: 0 8px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.books-card .intro {
|
||||
margin-left: 8px;
|
||||
}
|
||||
81
src/manage/qd/Books.tsx
Normal file
81
src/manage/qd/Books.tsx
Normal file
@@ -0,0 +1,81 @@
|
||||
import { Breadcrumb, Divider, Affix, Pagination, Skeleton, Result, Button, Card, Flex, Row, Col, Image, Typography } from 'antd';
|
||||
import { NavLink, useNavigate, useSearchParams } from 'react-router';
|
||||
import { useDb } from '../dbProvider';
|
||||
import { useEffect, useState } from 'react';
|
||||
import type { PagedData, QdBookInfo } from '../../types';
|
||||
import styles from './Books.module.css';
|
||||
|
||||
const { Paragraph } = Typography;
|
||||
|
||||
export default function Books() {
|
||||
const db = useDb();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [container, setContainer] = useState<HTMLDivElement | null>(null);
|
||||
const [page, setPage] = useState(Number(searchParams.get('page') || '1'));
|
||||
const [pageSize, setPageSize] = useState(Number(searchParams.get('pageSize') || '10'));
|
||||
const [totalCount, setTotalCount] = useState<number | null>(null);
|
||||
const [pageData, setPageData] = useState<PagedData<QdBookInfo> | null>(null);
|
||||
const [err, setErr] = useState<string | null>(null);
|
||||
const navigate = useNavigate();
|
||||
async function loadPage() {
|
||||
const data = await db.getQdBooks(page, pageSize);
|
||||
setPageData(data);
|
||||
setTotalCount(data.total);
|
||||
}
|
||||
function handle() {
|
||||
setPageData(null);
|
||||
loadPage().catch(e => {
|
||||
setErr(e instanceof Error ? e.message : String(e));
|
||||
});
|
||||
}
|
||||
useEffect(() => {
|
||||
handle();
|
||||
}, [page, pageSize]);
|
||||
return (
|
||||
<>
|
||||
<Breadcrumb items={
|
||||
[{
|
||||
title: <NavLink to="/">主页</NavLink>
|
||||
}, {
|
||||
title: '起点'
|
||||
}, {
|
||||
title: '按书籍管理'
|
||||
}]
|
||||
} />
|
||||
<Divider />
|
||||
<div ref={setContainer}>
|
||||
{totalCount !== null && (<Affix target={() => container}>
|
||||
<Pagination
|
||||
total={totalCount}
|
||||
pageSize={pageSize}
|
||||
pageSizeOptions={[10, 20, 50, 100]}
|
||||
onChange={(page, pageSize) => { setPage(page); setPageSize(pageSize); setSearchParams({ page: String(page), pageSize: String(pageSize) }); }}
|
||||
showTotal={(total, range) => `共 ${total} 条,当前显示 ${range[0]} - ${range[1]} 条`}
|
||||
showSizeChanger={true}
|
||||
/>
|
||||
</Affix>)}
|
||||
{!pageData && !err && <Skeleton active />}
|
||||
{err && <Result
|
||||
status="error"
|
||||
title="数据加载失败"
|
||||
extra={<Button type="primary" onClick={() => { setErr(null); handle(); }}>重试</Button>} />}
|
||||
{pageData && <Flex>
|
||||
{pageData.items.map(book => (
|
||||
<Card key={book.id} className={styles['books-card']} onClick={() => navigate(`/qd/book/${book.id}`)}>
|
||||
<Row>
|
||||
<Col span={6}>
|
||||
<Image src={book.bookInfo.imgUrl} preview={false} />
|
||||
</Col>
|
||||
<Col span={18}>
|
||||
<h3 className={styles.name}>{book.bookName}</h3>
|
||||
<Paragraph className={styles.author}>{book.bookInfo.pageJson.authorInfo.authorName} 著</Paragraph>
|
||||
<Paragraph className={styles.intro} ellipsis={{rows: 3}}>{book.intro}</Paragraph>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
))}
|
||||
</Flex>}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user