Story排版修改
This commit is contained in:
182
src/pages/story/components/TimelineItem/TimelineItem.tsx
Normal file
182
src/pages/story/components/TimelineItem/TimelineItem.tsx
Normal file
@@ -0,0 +1,182 @@
|
||||
import {DeleteOutlined, DownOutlined, EditOutlined, PlusOutlined, UpOutlined} from '@ant-design/icons';
|
||||
import {useIntl, useRequest} from '@umijs/max';
|
||||
import { Button, Card, Popconfirm, message } from 'antd';
|
||||
import React, {useState} from 'react';
|
||||
import {queryStoryItemImages, removeStoryItem} from '../../service';
|
||||
import useStyles from './index.style';
|
||||
import {StoryItem} from "@/pages/story/data";
|
||||
import TimelineImage from "@/components/TimelineImage";
|
||||
import TimelineItemDrawer from '../TimelineItemDrawer';
|
||||
|
||||
const TimelineItem: React.FC<{
|
||||
item: StoryItem;
|
||||
handleOption: (item: StoryItem, option: 'add' | 'edit' | 'addSubItem' | 'editSubItem') => void;
|
||||
refresh: () => void;
|
||||
}> = ({ item, handleOption, refresh }) => {
|
||||
const { styles } = useStyles();
|
||||
const intl = useIntl();
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const [showActions, setShowActions] = useState(false);
|
||||
const [subItemsExpanded, setSubItemsExpanded] = useState(false);
|
||||
const [openDetail, setOpenDetail] = useState(false)
|
||||
const { data: imagesList } = useRequest(
|
||||
async () => {
|
||||
return await queryStoryItemImages(item.instanceId);
|
||||
},
|
||||
);
|
||||
const handleDelete = async () => {
|
||||
try {
|
||||
if (!item.instanceId) return;
|
||||
const response = await removeStoryItem(item.instanceId);
|
||||
if (response.code === 200) {
|
||||
message.success(intl.formatMessage({ id: 'story.deleteSuccess' }));
|
||||
refresh();
|
||||
} else {
|
||||
message.error(intl.formatMessage({ id: 'story.deleteFailed' }));
|
||||
}
|
||||
} catch (error) {
|
||||
message.error(intl.formatMessage({ id: 'story.deleteFailed' }));
|
||||
}
|
||||
};
|
||||
const toggleDescription = () => {
|
||||
setExpanded(!expanded);
|
||||
};
|
||||
|
||||
const toggleSubItems = () => {
|
||||
setSubItemsExpanded(!subItemsExpanded);
|
||||
};
|
||||
|
||||
const displayedDescription = expanded
|
||||
? item.description
|
||||
: item.description?.substring(0, 100) + (item.description && item.description.length > 100 ? '...' : '');
|
||||
|
||||
return (
|
||||
<Card
|
||||
className={styles.timelineItem}
|
||||
title={item.title}
|
||||
onMouseEnter={() => setShowActions(true)}
|
||||
onMouseLeave={() => setShowActions(false)}
|
||||
onClick={() => setOpenDetail(true)}
|
||||
extra={
|
||||
<div
|
||||
className={styles.actions}
|
||||
>
|
||||
{showActions && (
|
||||
<>
|
||||
<Button
|
||||
type="text"
|
||||
icon={<EditOutlined />}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleOption(item, 'editSubItem');
|
||||
}}
|
||||
aria-label={intl.formatMessage({ id: 'story.edit' })}
|
||||
/>
|
||||
<Button
|
||||
type="text"
|
||||
icon={<PlusOutlined />}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleOption(item, 'addSubItem');
|
||||
}}
|
||||
aria-label={intl.formatMessage({ id: 'story.addSubItem' })}
|
||||
/>
|
||||
<Popconfirm
|
||||
title={intl.formatMessage({ id: 'story.deleteConfirm' })}
|
||||
description={intl.formatMessage({ id: 'story.deleteConfirmDescription' })}
|
||||
onConfirm={(e) => {
|
||||
e?.stopPropagation();
|
||||
handleDelete()
|
||||
}}
|
||||
okText={intl.formatMessage({ id: 'story.yes' })}
|
||||
cancelText={intl.formatMessage({ id: 'story.no' })}
|
||||
>
|
||||
<Button
|
||||
type="text"
|
||||
icon={<DeleteOutlined />}
|
||||
danger
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
aria-label={intl.formatMessage({ id: 'story.delete' })}
|
||||
/>
|
||||
</Popconfirm>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
// onClick={() => onDetail(item)}
|
||||
hoverable
|
||||
>
|
||||
<div className={styles.content}>
|
||||
<div className={styles.date}>
|
||||
{item.storyItemTime} {item.location ? `创建于${item.location}` : ''}
|
||||
</div>
|
||||
<div className={styles.description}>
|
||||
{displayedDescription}
|
||||
{item.description && item.description.length > 100 && (
|
||||
<Button
|
||||
type="link"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
toggleDescription();
|
||||
}}
|
||||
>
|
||||
{expanded
|
||||
? intl.formatMessage({ id: 'story.showLess' })
|
||||
: intl.formatMessage({ id: 'story.showMore' })}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
{imagesList && imagesList.length > 0 && (
|
||||
<>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '10px', marginBottom: '20px' }}>
|
||||
{imagesList.map((imageInstanceId, index) => (
|
||||
<TimelineImage
|
||||
key={imageInstanceId + index}
|
||||
title={imageInstanceId}
|
||||
imageInstanceId={imageInstanceId}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{item.subItems && item.subItems.length > 0 && (
|
||||
<div className={styles.subItems}>
|
||||
<div
|
||||
className={styles.subItemsHeader}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
toggleSubItems();
|
||||
}}
|
||||
>
|
||||
<span>
|
||||
{intl.formatMessage({ id: 'story.subItems' })} ({item.subItems.length})
|
||||
</span>
|
||||
{subItemsExpanded ? <UpOutlined /> : <DownOutlined />}
|
||||
</div>
|
||||
{subItemsExpanded && (
|
||||
<div className={styles.subItemsList}>
|
||||
{item.subItems.map((subItem) => (
|
||||
<div key={subItem.id} className={styles.subItem}>
|
||||
<div className={styles.subItemDate}>
|
||||
{item.storyItemTime} {item.location ? `创建于${item.location}` : ''}
|
||||
</div>
|
||||
<div className={styles.subItemContent}>
|
||||
{subItem.description}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<TimelineItemDrawer
|
||||
storyItem={item}
|
||||
open={openDetail}
|
||||
setOpen={setOpenDetail}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default TimelineItem;
|
||||
Reference in New Issue
Block a user