feat:窗口变动后日志高度自动更新

This commit is contained in:
1708-huayu 2025-07-24 18:40:43 +08:00
parent a2aced4c85
commit 24c01d4dc8
4 changed files with 178 additions and 35 deletions

View File

@ -1,13 +1,17 @@
import React, {useEffect, useRef, useState} from 'react';
import {Avatar, Dropdown, Input, List, MenuProps, message} from 'antd';
import React, {Fragment, useEffect, useRef, useState} from 'react';
import {Dropdown, List, MenuProps, message, Popconfirm} from 'antd';
import VirtualList from 'rc-virtual-list';
import {Button, Drawer} from 'antd';
import {ListDiary, SelectDiary} from "@/components/type/Diary";
import TextArea from "antd/es/input/TextArea";
import style from "@/components/DiaryOption.module.css"
import dayjs from "dayjs";
import {addTaskLogAPI} from "@/components/service/Diary";
import {addTaskLogAPI, deleteTaskLogByIdAPI, editEnableFlagAPI} from "@/components/service/Diary";
import {ListRef} from "rc-virtual-list/lib/List";
import {copyToClipboard} from "@/lib/copyToClipboard";
import {useWindowSize} from "@/hooks/useWindowSize";
import {DetailModelForm} from "@/ui/task/project/DetailModelForm";
import {OPERATION_BUTTON_TYPE} from "@/lib/task/project/data";
const DiaryOption = (props: SelectDiary) => {
// 抽屉 start
@ -19,9 +23,13 @@ const DiaryOption = (props: SelectDiary) => {
setOpen(false);
};
// 抽屉 end
const [shouldScroll,setShouldScroll] = React.useState(true);
const [shouldScroll, setShouldScroll] = React.useState(true);
// 设置高度 start
const { height } = useWindowSize();
const [containerHeight, setContainerHeight] = useState(400);
useEffect(() => {
setDiaryList([])
}, []);
useEffect(() => {
if (!open) return;
// 使用 setTimeout 确保 Drawer 内容已渲染
@ -47,7 +55,7 @@ const DiaryOption = (props: SelectDiary) => {
// observer.observe(contentRef.current);
//
// return () => observer.disconnect();
}, [open]);
}, [open,height]);
// 设置高度 end
// 头按钮设置 start
@ -91,6 +99,9 @@ const DiaryOption = (props: SelectDiary) => {
}
const appendData = (showMessage = true) => {
if (!open){
return
}
const fakeDataUrl = process.env.NEXT_PUBLIC_TODO_REQUEST_URL + `/task/message/diary/select`;
fetch(fakeDataUrl, {
method: 'POST', headers: {
@ -118,9 +129,7 @@ const DiaryOption = (props: SelectDiary) => {
useEffect(() => {
appendData(false);
// 视口高度
window.innerHeight
}, []);
}, [open]);
useEffect(() => {
console.log("处理日志集合", diaryList)
@ -171,13 +180,13 @@ const DiaryOption = (props: SelectDiary) => {
// 条件滚动
useEffect(() => {
console.log({shouldScroll},{listRef})
console.log({shouldScroll}, {listRef})
if (shouldScroll && listRef.current) {
listRef.current.scrollTo({
top: 99999,
});
}
}, [diaryList, shouldScroll,open]);
}, [diaryList, shouldScroll, open]);
// 滚动处理 end
// 点击操作 start
const [clickTaskDiary, setClickTaskDiary] = useState<ListDiary>()
@ -188,34 +197,103 @@ const DiaryOption = (props: SelectDiary) => {
setClickTaskDiary(item)
}
}
const items: MenuProps['items'] = [
// 删除操作
const [popConfirmOpen, setPopConfirmOpen] = useState(false);
const [popConfirmLoading, setPopConfirmLoading] = useState(false);
const popConfirmOk = () => {
setPopConfirmLoading(true)
if (clickTaskDiary){
deleteTaskLogByIdAPI(clickTaskDiary.id).then(res=>{
if (res.data.status.success){
setDiaryList(diaryList.filter(taskLog => taskLog.id != clickTaskDiary.id))
message.info("删除成功")
setPopConfirmLoading(false)
setPopConfirmOpen(false)
}else {
message.error(res.data.status.message)
}
})
}
}
const handleCancel = () =>{
setPopConfirmOpen(false)
}
const editEnableFlag = (enableFlag:string) => {
if (clickTaskDiary){
editEnableFlagAPI(clickTaskDiary.id,enableFlag).then(res=>{
if (res.data.status.success){
setDiaryList(diaryList.map(taskLog => {
if(taskLog.id == clickTaskDiary.id){
taskLog.enableFlag = enableFlag;
}
return taskLog;
}))
message.info("设置成功")
}else {
message.error(res.data.status.message)
}
})
}
}
const [addTaskOpen,setAddTaskOpen] = useState(false)
const commonItems: MenuProps['items'] = [
{
label: '复制',
key: '1',
onClick: () => {
copyToClipboard(clickTaskDiary!.description)
}
},
{
label: '失效',
key: '2',
},
{
label: '创建计划',
key: '3',
onClick:()=>{
// 打开添加任务窗口
setAddTaskOpen(true)
}
},
{
label: '删除',
key: '4',
onClick: () => {
setPopConfirmOpen(true)
}
},
{
label: '取消',
key: '5',
onClick:()=>{
setClickTaskDiary(undefined)
}
},
]
const items: MenuProps['items'] = [
];
items.push(...commonItems)
items.splice(1,0,{
label: '失效',
key: '2',
onClick:()=>{
editEnableFlag("0")
},
})
const itemsEnable: MenuProps['items'] = [
];
itemsEnable.push(...commonItems)
itemsEnable.splice(1,0,{
label: '生效',
key: '2',
onClick:()=>{
editEnableFlag("1")
},
})
// 点击操作 end
return (
<>
<Fragment>
<Button type="primary" onClick={showDrawer}>
</Button>
@ -309,26 +387,45 @@ const DiaryOption = (props: SelectDiary) => {
</div>
</div>
: <div className={style.logTaskContent} key={item.id}>
<Dropdown menu={{items}} trigger={['contextMenu']}>
<div
className={`${style.detailLine} ${item.id === clickTaskDiary?.id ? style.detailLineClick : ''}`}
onClick={() => onClickTAskDiary(item, "L")}
onContextMenu={() => onClickTAskDiary(item, "R")}>
<text
style={{
textDecoration: item.enableFlag === '0' && currentIndex === 0 ? 'line-through' : '',
whiteSpace: 'pre-line'
}}>
{item.description}
</text>
</div>
<Dropdown menu={{items: (item.enableFlag == "1" ? items : itemsEnable)}}
trigger={['contextMenu']}>
<Popconfirm
title="警告"
description={`确认要删除日志:${item.description.length > 5 ? item.description.substring(0, 5) + '...' : item.description}?`}
open={popConfirmOpen&&clickTaskDiary?.id==item.id}
onConfirm={popConfirmOk}
okButtonProps={{loading: popConfirmLoading}}
onCancel={handleCancel}
okText="Yes"
cancelText="No"
>
<div
className={`${style.detailLine} ${item.id === clickTaskDiary?.id ? style.detailLineClick : ''}`}
onClick={() => onClickTAskDiary(item, "L")}
onContextMenu={() => onClickTAskDiary(item, "R")}>
<text
style={{
textDecoration: item.enableFlag === '0' && currentIndex === 0 ? 'line-through' : '',
whiteSpace: 'pre-line'
}}>
{item.description}
</text>
</div>
</Popconfirm>
</Dropdown>
</div>
)}
</VirtualList>
</List>
</Drawer>
</>
{addTaskOpen&&<DetailModelForm pid={props.taskId}
operationId={OPERATION_BUTTON_TYPE.ADD_CHILD}
description={"新增计划"}
open={addTaskOpen}
haveButton={false}
reloadData={()=>setAddTaskOpen(false)}
/>}
</Fragment>
);
};
export default DiaryOption;

View File

@ -7,3 +7,9 @@ export const addTaskLogAPI= (data:AddDiary):Promise<AxiosResponse<ResponseVO<Lis
return httpReq.post(process.env.NEXT_PUBLIC_TODO_REQUEST_URL + "/task/message/diary",
data)
}
export const deleteTaskLogByIdAPI = (id:string) => {
return httpReq.delete( process.env.NEXT_PUBLIC_TODO_REQUEST_URL+`/task/message/diary?id=${id}`);
}
export const editEnableFlagAPI = (id:string,enableFlag:string) => {
return httpReq.put( process.env.NEXT_PUBLIC_TODO_REQUEST_URL+`/task/message/diary/enable?id=${id}&enableFlag=${enableFlag}`);
}

View File

@ -0,0 +1,21 @@
import { useState, useEffect } from 'react';
export function useWindowSize() {
const [windowSize, setWindowSize] = useState({
width: window.innerWidth,
height: window.innerHeight,
});
useEffect(() => {
const handleResize = () => {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return windowSize;
}

View File

@ -2,7 +2,7 @@ import {PlusOutlined, QuestionCircleOutlined} from '@ant-design/icons';
import {
ModalForm,
ProForm,
ProFormDateRangePicker, ProFormDateTimeRangePicker,
ProFormDateTimeRangePicker,
ProFormSelect,
ProFormText, ProFormTextArea, ProFormTreeSelect,
} from '@ant-design/pro-components';
@ -29,6 +29,8 @@ export type DetailModelFormProps = {
operationId: OPERATION_BUTTON_TYPE,
// 标题描述
description: string,
// 任务内容描述
taskContent?:string,
// 是否打开界面,用于非按钮操作
open: boolean,
// 使用按钮操作
@ -42,12 +44,14 @@ export type PidSelectTree = { label: string; value: string; pid: string; childre
export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
console.log("DetailModelForm:props:", props)
const [closeButton,setCloseButton] =useState(false)
const [form] = Form.useForm<DataType>();
const [requestTask,setRequestTask]=useState<DataType>()
const [editFormDisable, setEditFormDisable] = useState(props.operationId === OPERATION_BUTTON_TYPE.DETAIL)
// 团队第一层 pid必须为0
const [taskType, setTaskType] = useState('0')
useEffect(() => {
setCloseButton(false)
if (props.itemId != undefined && (
props.operationId === OPERATION_BUTTON_TYPE.DETAIL || props.operationId === OPERATION_BUTTON_TYPE.UPDATE)) {
getTask(props.itemId).then(task => {
@ -100,7 +104,7 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
return (
<ModalForm<DataType>
title={props.description}
open={props.open && !props.haveButton}
open={props.open && !props.haveButton&&!closeButton}
trigger={props.haveButton ?
<Button type="primary">
<PlusOutlined/>
@ -109,6 +113,12 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
}
form={form}
autoFocusFirstInput
onOpenChange={(state)=>{
console.log("state",{state})
if(!state) {
setCloseButton(state)
}
}}
modalProps={{
destroyOnClose: true,
onCancel: () => {
@ -118,7 +128,8 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
}}
submitter={props.itemId !== undefined && props.itemId !== '-1' ? {
render: (prop, defaultDoms) => {
return [
prop.resetButtonProps
let result = [
editFormDisable ? <Button
key="edit"
onClick={() => {
@ -154,8 +165,16 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
</Popconfirm> : undefined
,
requestTask&&requestTask.id?<DiaryOption taskId={requestTask.id} taskName={requestTask.name}/>:undefined,
...defaultDoms
];
]
// 非新增或者编辑状态不展示
if (!editFormDisable) {
result.push(...defaultDoms)
}else {
result.push(<Button type="primary" onClick={()=>setCloseButton(true)}>
</Button>)
}
return result;
},
} : undefined}
onFinish={async (values) => {