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 React, {Fragment, useEffect, useRef, useState} from 'react';
import {Avatar, Dropdown, Input, List, MenuProps, message} from 'antd'; import {Dropdown, List, MenuProps, message, Popconfirm} from 'antd';
import VirtualList from 'rc-virtual-list'; import VirtualList from 'rc-virtual-list';
import {Button, Drawer} from 'antd'; import {Button, Drawer} from 'antd';
import {ListDiary, SelectDiary} from "@/components/type/Diary"; import {ListDiary, SelectDiary} from "@/components/type/Diary";
import TextArea from "antd/es/input/TextArea"; import TextArea from "antd/es/input/TextArea";
import style from "@/components/DiaryOption.module.css" import style from "@/components/DiaryOption.module.css"
import dayjs from "dayjs"; 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 {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) => { const DiaryOption = (props: SelectDiary) => {
// 抽屉 start // 抽屉 start
@ -19,9 +23,13 @@ const DiaryOption = (props: SelectDiary) => {
setOpen(false); setOpen(false);
}; };
// 抽屉 end // 抽屉 end
const [shouldScroll,setShouldScroll] = React.useState(true); const [shouldScroll, setShouldScroll] = React.useState(true);
// 设置高度 start // 设置高度 start
const { height } = useWindowSize();
const [containerHeight, setContainerHeight] = useState(400); const [containerHeight, setContainerHeight] = useState(400);
useEffect(() => {
setDiaryList([])
}, []);
useEffect(() => { useEffect(() => {
if (!open) return; if (!open) return;
// 使用 setTimeout 确保 Drawer 内容已渲染 // 使用 setTimeout 确保 Drawer 内容已渲染
@ -47,7 +55,7 @@ const DiaryOption = (props: SelectDiary) => {
// observer.observe(contentRef.current); // observer.observe(contentRef.current);
// //
// return () => observer.disconnect(); // return () => observer.disconnect();
}, [open]); }, [open,height]);
// 设置高度 end // 设置高度 end
// 头按钮设置 start // 头按钮设置 start
@ -91,6 +99,9 @@ const DiaryOption = (props: SelectDiary) => {
} }
const appendData = (showMessage = true) => { const appendData = (showMessage = true) => {
if (!open){
return
}
const fakeDataUrl = process.env.NEXT_PUBLIC_TODO_REQUEST_URL + `/task/message/diary/select`; const fakeDataUrl = process.env.NEXT_PUBLIC_TODO_REQUEST_URL + `/task/message/diary/select`;
fetch(fakeDataUrl, { fetch(fakeDataUrl, {
method: 'POST', headers: { method: 'POST', headers: {
@ -118,9 +129,7 @@ const DiaryOption = (props: SelectDiary) => {
useEffect(() => { useEffect(() => {
appendData(false); appendData(false);
// 视口高度 }, [open]);
window.innerHeight
}, []);
useEffect(() => { useEffect(() => {
console.log("处理日志集合", diaryList) console.log("处理日志集合", diaryList)
@ -171,13 +180,13 @@ const DiaryOption = (props: SelectDiary) => {
// 条件滚动 // 条件滚动
useEffect(() => { useEffect(() => {
console.log({shouldScroll},{listRef}) console.log({shouldScroll}, {listRef})
if (shouldScroll && listRef.current) { if (shouldScroll && listRef.current) {
listRef.current.scrollTo({ listRef.current.scrollTo({
top: 99999, top: 99999,
}); });
} }
}, [diaryList, shouldScroll,open]); }, [diaryList, shouldScroll, open]);
// 滚动处理 end // 滚动处理 end
// 点击操作 start // 点击操作 start
const [clickTaskDiary, setClickTaskDiary] = useState<ListDiary>() const [clickTaskDiary, setClickTaskDiary] = useState<ListDiary>()
@ -188,34 +197,103 @@ const DiaryOption = (props: SelectDiary) => {
setClickTaskDiary(item) 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: '复制', label: '复制',
key: '1', key: '1',
onClick: () => { onClick: () => {
copyToClipboard(clickTaskDiary!.description)
} }
}, },
{
label: '失效',
key: '2',
},
{ {
label: '创建计划', label: '创建计划',
key: '3', key: '3',
onClick:()=>{
// 打开添加任务窗口
setAddTaskOpen(true)
}
}, },
{ {
label: '删除', label: '删除',
key: '4', key: '4',
onClick: () => {
setPopConfirmOpen(true)
}
}, },
{ {
label: '取消', label: '取消',
key: '5', 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 // 点击操作 end
return ( return (
<> <Fragment>
<Button type="primary" onClick={showDrawer}> <Button type="primary" onClick={showDrawer}>
</Button> </Button>
@ -309,26 +387,45 @@ const DiaryOption = (props: SelectDiary) => {
</div> </div>
</div> </div>
: <div className={style.logTaskContent} key={item.id}> : <div className={style.logTaskContent} key={item.id}>
<Dropdown menu={{items}} trigger={['contextMenu']}> <Dropdown menu={{items: (item.enableFlag == "1" ? items : itemsEnable)}}
<div trigger={['contextMenu']}>
className={`${style.detailLine} ${item.id === clickTaskDiary?.id ? style.detailLineClick : ''}`} <Popconfirm
onClick={() => onClickTAskDiary(item, "L")} title="警告"
onContextMenu={() => onClickTAskDiary(item, "R")}> description={`确认要删除日志:${item.description.length > 5 ? item.description.substring(0, 5) + '...' : item.description}?`}
<text open={popConfirmOpen&&clickTaskDiary?.id==item.id}
style={{ onConfirm={popConfirmOk}
textDecoration: item.enableFlag === '0' && currentIndex === 0 ? 'line-through' : '', okButtonProps={{loading: popConfirmLoading}}
whiteSpace: 'pre-line' onCancel={handleCancel}
}}> okText="Yes"
{item.description} cancelText="No"
</text> >
</div> <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> </Dropdown>
</div> </div>
)} )}
</VirtualList> </VirtualList>
</List> </List>
</Drawer> </Drawer>
</> {addTaskOpen&&<DetailModelForm pid={props.taskId}
operationId={OPERATION_BUTTON_TYPE.ADD_CHILD}
description={"新增计划"}
open={addTaskOpen}
haveButton={false}
reloadData={()=>setAddTaskOpen(false)}
/>}
</Fragment>
); );
}; };
export default DiaryOption; 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", return httpReq.post(process.env.NEXT_PUBLIC_TODO_REQUEST_URL + "/task/message/diary",
data) 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 { import {
ModalForm, ModalForm,
ProForm, ProForm,
ProFormDateRangePicker, ProFormDateTimeRangePicker, ProFormDateTimeRangePicker,
ProFormSelect, ProFormSelect,
ProFormText, ProFormTextArea, ProFormTreeSelect, ProFormText, ProFormTextArea, ProFormTreeSelect,
} from '@ant-design/pro-components'; } from '@ant-design/pro-components';
@ -29,6 +29,8 @@ export type DetailModelFormProps = {
operationId: OPERATION_BUTTON_TYPE, operationId: OPERATION_BUTTON_TYPE,
// 标题描述 // 标题描述
description: string, description: string,
// 任务内容描述
taskContent?:string,
// 是否打开界面,用于非按钮操作 // 是否打开界面,用于非按钮操作
open: boolean, open: boolean,
// 使用按钮操作 // 使用按钮操作
@ -42,12 +44,14 @@ export type PidSelectTree = { label: string; value: string; pid: string; childre
export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => { export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
console.log("DetailModelForm:props:", props) console.log("DetailModelForm:props:", props)
const [closeButton,setCloseButton] =useState(false)
const [form] = Form.useForm<DataType>(); const [form] = Form.useForm<DataType>();
const [requestTask,setRequestTask]=useState<DataType>() const [requestTask,setRequestTask]=useState<DataType>()
const [editFormDisable, setEditFormDisable] = useState(props.operationId === OPERATION_BUTTON_TYPE.DETAIL) const [editFormDisable, setEditFormDisable] = useState(props.operationId === OPERATION_BUTTON_TYPE.DETAIL)
// 团队第一层 pid必须为0 // 团队第一层 pid必须为0
const [taskType, setTaskType] = useState('0') const [taskType, setTaskType] = useState('0')
useEffect(() => { useEffect(() => {
setCloseButton(false)
if (props.itemId != undefined && ( if (props.itemId != undefined && (
props.operationId === OPERATION_BUTTON_TYPE.DETAIL || props.operationId === OPERATION_BUTTON_TYPE.UPDATE)) { props.operationId === OPERATION_BUTTON_TYPE.DETAIL || props.operationId === OPERATION_BUTTON_TYPE.UPDATE)) {
getTask(props.itemId).then(task => { getTask(props.itemId).then(task => {
@ -100,7 +104,7 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
return ( return (
<ModalForm<DataType> <ModalForm<DataType>
title={props.description} title={props.description}
open={props.open && !props.haveButton} open={props.open && !props.haveButton&&!closeButton}
trigger={props.haveButton ? trigger={props.haveButton ?
<Button type="primary"> <Button type="primary">
<PlusOutlined/> <PlusOutlined/>
@ -109,6 +113,12 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
} }
form={form} form={form}
autoFocusFirstInput autoFocusFirstInput
onOpenChange={(state)=>{
console.log("state",{state})
if(!state) {
setCloseButton(state)
}
}}
modalProps={{ modalProps={{
destroyOnClose: true, destroyOnClose: true,
onCancel: () => { onCancel: () => {
@ -118,7 +128,8 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
}} }}
submitter={props.itemId !== undefined && props.itemId !== '-1' ? { submitter={props.itemId !== undefined && props.itemId !== '-1' ? {
render: (prop, defaultDoms) => { render: (prop, defaultDoms) => {
return [ prop.resetButtonProps
let result = [
editFormDisable ? <Button editFormDisable ? <Button
key="edit" key="edit"
onClick={() => { onClick={() => {
@ -154,8 +165,16 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
</Popconfirm> : undefined </Popconfirm> : undefined
, ,
requestTask&&requestTask.id?<DiaryOption taskId={requestTask.id} taskName={requestTask.name}/>: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} } : undefined}
onFinish={async (values) => { onFinish={async (values) => {