| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- import React, { useState, useMemo } from 'react';
- import { Link, useParams } from 'react-router-dom';
- import {
- List,
- Row,
- Col,
- Input,
- Button,
- Popconfirm,
- Space,
- Typography,
- message,
- } from 'antd';
- import {
- PlusOutlined,
- UploadOutlined,
- AimOutlined,
- EditOutlined,
- StarFilled,
- StarOutlined,
- DeleteOutlined,
- } from '@ant-design/icons';
- import { useGetDict } from '../apis/dicts';
- import type { WordResult } from '../apis/words';
- import { useUpdateWord, useDeleteWord } from '../apis/words';
- import WordModal from '../components/WordModal';
- import UploadModal from '../components/UploadModal';
- import styles from './DictPage.module.css';
- const { Text } = Typography;
- const DictPage: React.FC = () => {
- const [search, setSearch] = useState('');
- const [initialWord, setInitialWord] = useState<WordResult>();
- const [wordModalOpen, setWordModalOpen] = useState(false);
- const [uploadModalOpen, setUploadModalOpen] = useState(false);
- const { dictID = '' } = useParams();
- const {
- data: { dict, words } = {},
- loading,
- refresh,
- mutate,
- } = useGetDict({
- id: parseInt(dictID),
- });
- const updateWord = useUpdateWord();
- const deleteWord = useDeleteWord();
- const filteredWordsList = useMemo(
- () =>
- search
- ? words?.list.filter(
- word =>
- word.value.includes(search) ||
- word.meaning.includes(search) ||
- (dict?.extraTitle && word.extra.includes(search)),
- )
- : words?.list,
- [search, dict?.extraTitle, words?.list],
- );
- const mutateWordsList = (newWord: WordResult) => {
- if (dict && words) {
- const index = words.list.findIndex(value => value.id === newWord.id);
- mutate({
- dict,
- words: {
- total: words.total,
- list: [
- ...words.list.slice(0, index),
- newWord,
- ...words.list.slice(index + 1),
- ],
- },
- });
- }
- };
- return (
- <div className={styles.wrapper}>
- <List
- bordered
- header={
- <Row justify="space-between">
- <Col>
- <Input
- allowClear
- placeholder="搜索"
- onChange={e => setSearch(e.target.value)}
- />
- </Col>
- {dict && (
- <Col>
- <Button
- type="link"
- icon={<PlusOutlined />}
- onClick={() => {
- setInitialWord(undefined);
- setWordModalOpen(true);
- }}
- >
- 创建新单词
- </Button>
- <Button
- type="link"
- icon={<UploadOutlined />}
- onClick={() => setUploadModalOpen(true)}
- >
- 上传 Excel
- </Button>
- <Link to={`/dicts/${dictID}/memo`}>
- <Button type="link" icon={<AimOutlined />}>
- 开始复习
- </Button>
- </Link>
- </Col>
- )}
- </Row>
- }
- loading={loading}
- dataSource={filteredWordsList}
- renderItem={word => (
- <List.Item
- actions={[
- <Button
- key="update"
- type="link"
- size="small"
- icon={<EditOutlined />}
- onClick={() => {
- setInitialWord(word);
- setWordModalOpen(true);
- }}
- />,
- <Button
- key="star"
- type="link"
- danger
- size="small"
- icon={word.star ? <StarFilled /> : <StarOutlined />}
- onClick={() =>
- void (async () => {
- try {
- const newWord = { ...word, star: !word.star };
- mutateWordsList(newWord);
- await updateWord(newWord);
- } catch (err) {
- if (err instanceof Error) {
- void message.error(err.message);
- }
- }
- })()
- }
- />,
- <Popconfirm
- key="delete"
- title="确定删除该单词?"
- onConfirm={() =>
- void (async () => {
- try {
- await deleteWord({ id: word.id });
- void message.success('删除成功');
- refresh();
- } catch (err) {
- if (err instanceof Error) {
- void message.error(err.message);
- }
- }
- })()
- }
- >
- <Button
- type="link"
- danger
- size="small"
- icon={<DeleteOutlined />}
- />
- </Popconfirm>,
- ]}
- >
- <List.Item.Meta
- title={
- <Space size="middle">
- {word.value}
- {dict?.extraTitle && (
- <Text type="secondary">{word.extra}</Text>
- )}
- </Space>
- }
- description={word.meaning}
- />
- </List.Item>
- )}
- pagination={{}}
- />
- {dict && (
- <>
- <WordModal
- dict={dict}
- initialWord={initialWord}
- refresh={refresh}
- open={wordModalOpen}
- onCancel={() => setWordModalOpen(false)}
- />
- <UploadModal
- dict={dict}
- refresh={refresh}
- open={uploadModalOpen}
- onCancel={() => setUploadModalOpen(false)}
- />
- </>
- )}
- </div>
- );
- };
- export default DictPage;
|