Compare commits
5 Commits
967da82d9d
...
e1a40a8980
Author | SHA1 | Date |
---|---|---|
|
e1a40a8980 | |
|
354fb92d28 | |
|
24c01d4dc8 | |
|
a2aced4c85 | |
|
db19c5e12c |
|
@ -1,8 +1,3 @@
|
||||||
.reverseScrollList {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column; /* 垂直反转 */
|
|
||||||
/*overflow-y: auto;*/
|
|
||||||
}
|
|
||||||
/* 容器样式 */
|
/* 容器样式 */
|
||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -55,7 +50,7 @@
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 4rpx 20rpx;
|
padding: 4rpx 20rpx;
|
||||||
border: solid;
|
border: solid;
|
||||||
border-radius: 20rpx;
|
border-radius: 0.5rem;
|
||||||
border-color: #1677FF;
|
border-color: #1677FF;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
import React, {useEffect, useState} from 'react';
|
import React, {Fragment, useEffect, useRef, useState} from 'react';
|
||||||
import {Avatar, Input, List, 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";
|
||||||
const CONTAINER_HEIGHT = 400;
|
import {copyToClipboard} from "@/lib/copyToClipboard";
|
||||||
const PAGE_SIZE = 20;
|
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
|
||||||
|
@ -21,6 +23,40 @@ const DiaryOption = (props: SelectDiary) => {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
};
|
};
|
||||||
// 抽屉 end
|
// 抽屉 end
|
||||||
|
const [shouldScroll, setShouldScroll] = React.useState(true);
|
||||||
|
// 设置高度 start
|
||||||
|
const { height } = useWindowSize();
|
||||||
|
const [containerHeight, setContainerHeight] = useState(400);
|
||||||
|
useEffect(() => {
|
||||||
|
setDiaryList([])
|
||||||
|
}, []);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!open) return;
|
||||||
|
// 使用 setTimeout 确保 Drawer 内容已渲染
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
const innerDiv = document.querySelector('.ant-drawer-body');
|
||||||
|
const titleButtonHeight = document.querySelector('.titleButton');
|
||||||
|
// clientHeight:可视高度(包括 padding,但不包括 border、margin 和滚动条)
|
||||||
|
// offsetHeight:总高度(包括 padding、border 和滚动条,但不包括 margin)
|
||||||
|
// scrollHeight:内容总高度(包括不可见部分)
|
||||||
|
if (innerDiv && titleButtonHeight) {
|
||||||
|
console.log(innerDiv.clientHeight)
|
||||||
|
setContainerHeight(innerDiv.clientHeight - titleButtonHeight.clientHeight)
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
// console.log({contentRef})
|
||||||
|
// const observer = new ResizeObserver((entries) => {
|
||||||
|
// const entry = entries[0];
|
||||||
|
// setContentHeight(entry.contentRect.height);
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// observer.observe(contentRef.current);
|
||||||
|
//
|
||||||
|
// return () => observer.disconnect();
|
||||||
|
}, [open,height]);
|
||||||
|
// 设置高度 end
|
||||||
|
|
||||||
// 头按钮设置 start
|
// 头按钮设置 start
|
||||||
const [currentIndex, setCurrentIndex] = useState(1);
|
const [currentIndex, setCurrentIndex] = useState(1);
|
||||||
|
@ -29,12 +65,19 @@ const DiaryOption = (props: SelectDiary) => {
|
||||||
const [diaryList, setDiaryList] = useState<ListDiary[]>([]);
|
const [diaryList, setDiaryList] = useState<ListDiary[]>([]);
|
||||||
const [diaryReduceList, setDiaryReduceList] = useState<ListDiary[]>([])
|
const [diaryReduceList, setDiaryReduceList] = useState<ListDiary[]>([])
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const noMore = {id: '0', keyId: 'o0',createdDate:new Date(), description: '没有更多了',taskId:props.taskId, enableFlag: 'day-separate'};
|
const noMore = {
|
||||||
|
id: '0',
|
||||||
|
keyId: 'o0',
|
||||||
|
createdDate: new Date(),
|
||||||
|
description: '没有更多了',
|
||||||
|
taskId: props.taskId,
|
||||||
|
enableFlag: 'day-separate'
|
||||||
|
};
|
||||||
const [noMoreFlag, setNoMoreFlag] = useState(false)
|
const [noMoreFlag, setNoMoreFlag] = useState(false)
|
||||||
const [sendValue,setSendValue] = useState<string>();
|
const [sendValue, setSendValue] = useState<string>();
|
||||||
const [sendValueFlag,setSendValueFlag] =useState(false);
|
const [sendValueFlag, setSendValueFlag] = useState(false);
|
||||||
const handleSend = ()=>{
|
const handleSend = () => {
|
||||||
if(sendValueFlag){
|
if (sendValueFlag) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setSendValueFlag(true);
|
setSendValueFlag(true);
|
||||||
|
@ -49,12 +92,16 @@ const DiaryOption = (props: SelectDiary) => {
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
setDiaryList([res.data.data, ...diaryList])
|
setDiaryList([res.data.data, ...diaryList])
|
||||||
setSendValue(undefined)
|
setSendValue(undefined)
|
||||||
|
setShouldScroll(true);
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
setSendValueFlag(false);
|
setSendValueFlag(false);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
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: {
|
||||||
|
@ -72,21 +119,29 @@ const DiaryOption = (props: SelectDiary) => {
|
||||||
setDiaryList(diaryList.concat(results));
|
setDiaryList(diaryList.concat(results));
|
||||||
setPage(page + 1);
|
setPage(page + 1);
|
||||||
showMessage && message.success(`${results.length} more items loaded!`);
|
showMessage && message.success(`${results.length} more items loaded!`);
|
||||||
|
if (!showMessage) {
|
||||||
|
if (listRef && listRef.current && typeof listRef.current.scrollTo == 'function') {
|
||||||
|
listRef.current.scrollTo({top: 9999999});
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
appendData(false);
|
appendData(false);
|
||||||
}, []);
|
}, [open]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("处理日志集合",diaryList)
|
console.log("处理日志集合", diaryList)
|
||||||
const returnResult: ListDiary[] = []
|
const returnResult: ListDiary[] = []
|
||||||
diaryList.filter(taskLog => {
|
diaryList.filter(taskLog => {
|
||||||
if (currentIndex === 0) { return true }
|
if (currentIndex === 0) {
|
||||||
else if (currentIndex === 1 && taskLog.enableFlag === "1") { return true }
|
return true
|
||||||
else if (currentIndex === 2 && taskLog.enableFlag === "0") { return true }
|
} else if (currentIndex === 1 && taskLog.enableFlag === "1") {
|
||||||
else return false;
|
return true
|
||||||
|
} else if (currentIndex === 2 && taskLog.enableFlag === "0") {
|
||||||
|
return true
|
||||||
|
} else return false;
|
||||||
}).reduce((map, taskLog) => {
|
}).reduce((map, taskLog) => {
|
||||||
if (!map.has(dayjs(taskLog.createdDate).format("YYYY-MM-DD"))) {
|
if (!map.has(dayjs(taskLog.createdDate).format("YYYY-MM-DD"))) {
|
||||||
map.set(dayjs(taskLog.createdDate).format("YYYY-MM-DD"), []);
|
map.set(dayjs(taskLog.createdDate).format("YYYY-MM-DD"), []);
|
||||||
|
@ -103,32 +158,150 @@ const DiaryOption = (props: SelectDiary) => {
|
||||||
createdDate: new Date()
|
createdDate: new Date()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
setDiaryReduceList(returnResult);
|
setDiaryReduceList(returnResult.reverse());
|
||||||
}, [diaryList]);
|
}, [diaryList, currentIndex]);
|
||||||
|
|
||||||
|
const listRef = useRef<ListRef>(null);
|
||||||
const onScroll = (e: React.UIEvent<HTMLElement, UIEvent>) => {
|
const onScroll = (e: React.UIEvent<HTMLElement, UIEvent>) => {
|
||||||
// Refer to: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#problems_and_solutions
|
// Refer to: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#problems_and_solutions
|
||||||
if (
|
// if (
|
||||||
Math.abs(e.currentTarget.scrollHeight - e.currentTarget.scrollTop - CONTAINER_HEIGHT) <= 1 &&
|
// Math.abs(e.currentTarget.scrollHeight - e.currentTarget.scrollTop - containerHeight) <= 1 &&
|
||||||
!noMoreFlag
|
// !noMoreFlag
|
||||||
) {
|
// ) {
|
||||||
|
// appendData();
|
||||||
|
// }
|
||||||
|
if (e.currentTarget.scrollTop === 0 && !noMoreFlag) {
|
||||||
appendData();
|
appendData();
|
||||||
|
setShouldScroll(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 数据 end
|
// 数据 end
|
||||||
|
// 滚动处理 start
|
||||||
|
|
||||||
|
// 条件滚动
|
||||||
|
useEffect(() => {
|
||||||
|
console.log({shouldScroll}, {listRef})
|
||||||
|
if (shouldScroll && listRef.current) {
|
||||||
|
listRef.current.scrollTo({
|
||||||
|
top: 99999,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [diaryList, shouldScroll, open]);
|
||||||
|
// 滚动处理 end
|
||||||
// 点击操作 start
|
// 点击操作 start
|
||||||
const [clickTaskDiary, setClickTaskDiary] = useState<ListDiary>()
|
const [clickTaskDiary, setClickTaskDiary] = useState<ListDiary>()
|
||||||
|
const onClickTAskDiary = (item: ListDiary, operate: string) => {
|
||||||
|
if (clickTaskDiary == item && operate == 'L') {
|
||||||
|
setClickTaskDiary(undefined)
|
||||||
|
} else {
|
||||||
|
setClickTaskDiary(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 删除操作
|
||||||
|
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: '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
|
// 点击操作 end
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Fragment>
|
||||||
<Button type="primary" onClick={showDrawer}>
|
<Button type="primary" onClick={showDrawer}>
|
||||||
日志心得
|
日志心得
|
||||||
</Button>
|
</Button>
|
||||||
<Drawer
|
<Drawer
|
||||||
style={{boxSizing:"border-box"}}
|
style={{boxSizing: "border-box"}}
|
||||||
|
styles={{
|
||||||
|
body: {padding: "0 24px"}
|
||||||
|
}}
|
||||||
mask={false}
|
mask={false}
|
||||||
title={props.taskName}
|
title={props.taskName}
|
||||||
closable={{'aria-label': 'Close Button'}}
|
closable={{'aria-label': 'Close Button'}}
|
||||||
|
@ -187,7 +360,8 @@ const DiaryOption = (props: SelectDiary) => {
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="displayFlexRow">
|
<div className="displayFlexRow titleButton"
|
||||||
|
style={{position: "sticky", top: "0", background: "white", zIndex: "100"}}>
|
||||||
<Button style={{flexGrow: 1}} onClick={() => setCurrentIndex(0)}
|
<Button style={{flexGrow: 1}} onClick={() => setCurrentIndex(0)}
|
||||||
type={currentIndex == 0 ? "primary" : "default"}>全部</Button>
|
type={currentIndex == 0 ? "primary" : "default"}>全部</Button>
|
||||||
<Button style={{flexGrow: 1}} onClick={() => setCurrentIndex(1)}
|
<Button style={{flexGrow: 1}} onClick={() => setCurrentIndex(1)}
|
||||||
|
@ -195,39 +369,64 @@ const DiaryOption = (props: SelectDiary) => {
|
||||||
<Button style={{flexGrow: 1}} onClick={() => setCurrentIndex(2)}
|
<Button style={{flexGrow: 1}} onClick={() => setCurrentIndex(2)}
|
||||||
type={currentIndex == 2 ? "primary" : "default"}>失效</Button>
|
type={currentIndex == 2 ? "primary" : "default"}>失效</Button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<List>
|
||||||
<List>
|
<VirtualList
|
||||||
<VirtualList
|
data={diaryReduceList}
|
||||||
data={diaryReduceList}
|
height={containerHeight}
|
||||||
height={CONTAINER_HEIGHT}
|
// itemHeight={47}
|
||||||
itemHeight={47}
|
itemKey="id"
|
||||||
itemKey="email"
|
onScroll={onScroll}
|
||||||
onScroll={onScroll}
|
// style={{height: "auto"}}
|
||||||
className={style.reverseScrollList}
|
ref={listRef}
|
||||||
>
|
>
|
||||||
{item => (
|
{item => (
|
||||||
item.enableFlag === 'day-separate' ?
|
item.enableFlag === 'day-separate' ?
|
||||||
<div className={style.container} key={item.keyId}>
|
<div className={style.container} key={item.keyId}>
|
||||||
<div className={style.lineWithText}>
|
<div className={style.lineWithText}>
|
||||||
<text className={style.centerText}>{item.description}</text>
|
<text className={style.centerText}>{item.description}</text>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
: <div className={style.logTaskContent} key={item.id}>
|
</div>
|
||||||
<div
|
: <div className={style.logTaskContent} key={item.id}>
|
||||||
className={`${style.detailLine} ${item.id === clickTaskDiary?.id ? style.detailLineClick : ''}`}
|
<Dropdown menu={{items: (item.enableFlag == "1" ? items : itemsEnable)}}
|
||||||
onClick={() => setClickTaskDiary(item)}>
|
trigger={['contextMenu']}>
|
||||||
<text
|
<Popconfirm
|
||||||
style={{textDecoration: item.enableFlag === '0' && currentIndex === 0 ? 'line-through' : ''}}>
|
title="警告"
|
||||||
{item.description}
|
description={`确认要删除日志:${item.description.length > 5 ? item.description.substring(0, 5) + '...' : item.description}?`}
|
||||||
</text>
|
open={popConfirmOpen&&clickTaskDiary?.id==item.id}
|
||||||
</div>
|
onConfirm={popConfirmOk}
|
||||||
</div>
|
okButtonProps={{loading: popConfirmLoading}}
|
||||||
)}
|
onCancel={handleCancel}
|
||||||
</VirtualList>
|
okText="Yes"
|
||||||
</List>
|
cancelText="No"
|
||||||
</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>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</VirtualList>
|
||||||
|
</List>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
</>
|
{addTaskOpen&&<DetailModelForm pid={props.taskId}
|
||||||
|
operationId={OPERATION_BUTTON_TYPE.ADD_CHILD}
|
||||||
|
description={"新增计划"}
|
||||||
|
open={addTaskOpen}
|
||||||
|
haveButton={false}
|
||||||
|
reloadData={()=>setAddTaskOpen(false)}
|
||||||
|
taskContent={clickTaskDiary?.description}
|
||||||
|
/>}
|
||||||
|
</Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default DiaryOption;
|
export default DiaryOption;
|
|
@ -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}`);
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import {unstable_noStore as noStore} from 'next/cache';
|
import {unstable_noStore as noStore} from 'next/cache';
|
||||||
import {AxiosResponse} from "axios";
|
import {AxiosResponse} from "axios";
|
||||||
import {httpReq} from "@/utils/axiosReq";
|
import {httpReq} from "@/utils/axiosReq";
|
||||||
import {DataType, DictType, Request, ResponseVO, ResultPage} from "@/lib/definitions";
|
import {DataType, DictType, Request, ResponseVO, ResultPage, TaskMessage} from "@/lib/definitions";
|
||||||
import {TaskWebSelectVO} from "@/lib/task/project/definitions";
|
import {TaskWebSelectVO} from "@/lib/task/project/definitions";
|
||||||
|
|
||||||
export async function getTaskTreeResult(requestParam: string): Promise<ResponseVO<ResultPage<DataType>>> {
|
export async function getTaskTreeResult(requestParam: string): Promise<ResponseVO<ResultPage<DataType>>> {
|
||||||
|
@ -52,12 +52,20 @@ export async function getTask(id: string): Promise<ResponseVO<DataType>> {
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function addTask(task: DataType): Promise<ResponseVO<string>> {
|
export function addTask(task: DataType): Promise<AxiosResponse<ResponseVO<TaskMessage>>> {
|
||||||
noStore();
|
noStore();
|
||||||
// 使用 Axios 发送 POST 请求添加数据
|
// 使用 Axios 发送 POST 请求添加数据
|
||||||
const response: AxiosResponse<ResponseVO<string>> = await httpReq.post(process.env.NEXT_PUBLIC_TODO_REQUEST_URL + '/task', task);
|
switch(task.taskType){
|
||||||
// 从响应中提取数据并返回
|
// 常规任务
|
||||||
return response.data;
|
case '0':return httpReq.post(process.env.NEXT_PUBLIC_TODO_REQUEST_URL + '/V2/task', task);
|
||||||
|
// 团队任务
|
||||||
|
case '1':return httpReq.post(process.env.NEXT_PUBLIC_TODO_REQUEST_URL + '/V2/task', task);
|
||||||
|
// 顺序
|
||||||
|
case '2':return httpReq.post(process.env.NEXT_PUBLIC_TODO_REQUEST_URL + '/task/step/sort', task);
|
||||||
|
// 周期
|
||||||
|
case '3':return httpReq.post(process.env.NEXT_PUBLIC_TODO_REQUEST_URL + '/task/schedule', task);
|
||||||
|
default:throw new Error("创建任务必选任务类型");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateTask(task: DataType): Promise<ResponseVO<string>> {
|
export async function updateTask(task: DataType): Promise<ResponseVO<string>> {
|
||||||
|
|
|
@ -268,6 +268,7 @@ const CalShow: React.FC = () => {
|
||||||
{open && <DetailModelForm operationId={operationId} description={description} open={open} haveButton={false}
|
{open && <DetailModelForm operationId={operationId} description={description} open={open} haveButton={false}
|
||||||
itemId={itemId}
|
itemId={itemId}
|
||||||
reloadData={reloadData} expectedStartTime={expectedStartTime}
|
reloadData={reloadData} expectedStartTime={expectedStartTime}
|
||||||
|
closeOpen={()=>setOpen(false)}
|
||||||
expectedEndTime={expectedEndTime}/>}
|
expectedEndTime={expectedEndTime}/>}
|
||||||
<DragAndDropCalendar
|
<DragAndDropCalendar
|
||||||
// 本地设置
|
// 本地设置
|
||||||
|
|
|
@ -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,10 +29,13 @@ export type DetailModelFormProps = {
|
||||||
operationId: OPERATION_BUTTON_TYPE,
|
operationId: OPERATION_BUTTON_TYPE,
|
||||||
// 标题描述
|
// 标题描述
|
||||||
description: string,
|
description: string,
|
||||||
|
// 任务内容描述
|
||||||
|
taskContent?: string,
|
||||||
// 是否打开界面,用于非按钮操作
|
// 是否打开界面,用于非按钮操作
|
||||||
open: boolean,
|
open: boolean,
|
||||||
// 使用按钮操作
|
// 使用按钮操作
|
||||||
haveButton: boolean,
|
haveButton: boolean,
|
||||||
|
closeOpen?: () => void,
|
||||||
expectedStartTime?: Dayjs,
|
expectedStartTime?: Dayjs,
|
||||||
expectedEndTime?: Dayjs,
|
expectedEndTime?: Dayjs,
|
||||||
// 重新加载数据
|
// 重新加载数据
|
||||||
|
@ -43,7 +46,7 @@ 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 [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')
|
||||||
|
@ -61,8 +64,8 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
|
||||||
task.data.expectedTimeRange = [task.data.expectedStartTime ? dayjs(task.data.expectedStartTime) : undefined,
|
task.data.expectedTimeRange = [task.data.expectedStartTime ? dayjs(task.data.expectedStartTime) : undefined,
|
||||||
task.data.expectedEndTime ? dayjs(task.data.expectedEndTime) : undefined];
|
task.data.expectedEndTime ? dayjs(task.data.expectedEndTime) : undefined];
|
||||||
form.setFieldsValue(task.data)
|
form.setFieldsValue(task.data)
|
||||||
if (task.data.pid=="0"){
|
if (task.data.pid == "0") {
|
||||||
form.setFieldValue("pid",undefined)
|
form.setFieldValue("pid", undefined)
|
||||||
}
|
}
|
||||||
setRequestTask(task.data)
|
setRequestTask(task.data)
|
||||||
console.log("form.setFieldsValue(task.data)" + JSON.stringify(task.data))
|
console.log("form.setFieldsValue(task.data)" + JSON.stringify(task.data))
|
||||||
|
@ -74,7 +77,9 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
|
||||||
} else if (props.operationId === OPERATION_BUTTON_TYPE.ADD || props.operationId === OPERATION_BUTTON_TYPE.ADD_CHILD) {
|
} else if (props.operationId === OPERATION_BUTTON_TYPE.ADD || props.operationId === OPERATION_BUTTON_TYPE.ADD_CHILD) {
|
||||||
let data = {
|
let data = {
|
||||||
'expectedTimeRange': [props.expectedStartTime ? props.expectedStartTime : dayjs(), props.expectedEndTime],
|
'expectedTimeRange': [props.expectedStartTime ? props.expectedStartTime : dayjs(), props.expectedEndTime],
|
||||||
'pid': props.pid
|
'pid': props.pid,
|
||||||
|
'description': props.taskContent,
|
||||||
|
'name': props.taskContent && props.taskContent?.length > 10 ? props.taskContent.substring(0, 10) : props.taskContent,
|
||||||
};
|
};
|
||||||
form.setFieldsValue(data)
|
form.setFieldsValue(data)
|
||||||
}
|
}
|
||||||
|
@ -112,22 +117,21 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
|
||||||
modalProps={{
|
modalProps={{
|
||||||
destroyOnClose: true,
|
destroyOnClose: true,
|
||||||
onCancel: () => {
|
onCancel: () => {
|
||||||
console.log('run');
|
|
||||||
props.reloadData?.();
|
props.reloadData?.();
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
readonly={editFormDisable}
|
||||||
submitter={props.itemId !== undefined && props.itemId !== '-1' ? {
|
submitter={props.itemId !== undefined && props.itemId !== '-1' ? {
|
||||||
render: (prop, defaultDoms) => {
|
render: (prop, defaultDoms) => {
|
||||||
return [
|
console.log("submitter render: ", {prop})
|
||||||
|
let result = [
|
||||||
editFormDisable ? <Button
|
editFormDisable ? <Button
|
||||||
key="edit"
|
key="edit"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
// props.submit();
|
// props.submit();
|
||||||
setEditFormDisable(false)
|
setEditFormDisable(false)
|
||||||
}}
|
}}
|
||||||
>
|
>编辑</Button> : undefined,
|
||||||
编辑
|
|
||||||
</Button> : 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 ?
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
key='delete'
|
key='delete'
|
||||||
|
@ -148,21 +152,50 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button type="primary" danger>
|
<Button type="primary" key="delete" danger>
|
||||||
删除
|
删除
|
||||||
</Button>
|
</Button>
|
||||||
</Popconfirm> : undefined
|
</Popconfirm> : undefined,
|
||||||
,
|
requestTask && requestTask.id ?
|
||||||
requestTask&&requestTask.id?<DiaryOption taskId={requestTask.id} taskName={requestTask.name}/>:undefined,
|
<DiaryOption key="diary" taskId={requestTask.id} taskName={requestTask.name}/> : undefined,
|
||||||
...defaultDoms
|
]
|
||||||
];
|
|
||||||
|
// 非新增或者编辑状态不展示
|
||||||
|
if (!editFormDisable) {
|
||||||
|
result.push(...defaultDoms)
|
||||||
|
} else {
|
||||||
|
result.push(<Button type="primary" key="join"
|
||||||
|
onClick={() => props.closeOpen?.()}>邀请小伙伴加入</Button>)
|
||||||
|
result.push(<Button type="primary" key="close"
|
||||||
|
onClick={() => props.closeOpen?.()}>关闭</Button>)
|
||||||
|
}
|
||||||
|
return result;
|
||||||
},
|
},
|
||||||
} : undefined}
|
} : {
|
||||||
|
render: (prop, defaultDoms) => {
|
||||||
|
console.log("submitter render: ", {prop}, {props},{taskType},{defaultDoms})
|
||||||
|
// if ( prop.searchConfig) {
|
||||||
|
// if (taskType == '1') {
|
||||||
|
// prop.searchConfig.submitText = "创建团队"
|
||||||
|
// }else {
|
||||||
|
// prop.searchConfig.submitText = "确认"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return defaultDoms;
|
||||||
|
const result = defaultDoms.filter(defaultButton=>defaultButton.key=='rest');
|
||||||
|
result.push(<Button type="primary" key="create-team" onClick={() => form.submit()}>{taskType=='1'?"创建团队":"确认"}
|
||||||
|
</Button>)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
onFinish={async (values) => {
|
onFinish={async (values) => {
|
||||||
console.log('Received values of form: ', values,{...requestTask,...values});
|
{/* onFinish 返回true关闭窗口,范湖false不关闭窗口 */
|
||||||
|
}
|
||||||
|
console.log('Received values of form: ', values, {...requestTask, ...values});
|
||||||
if (requestTask) {
|
if (requestTask) {
|
||||||
const {sortNo}=requestTask;
|
const {sortNo} = requestTask;
|
||||||
values.sortNo=sortNo;
|
values.sortNo = sortNo;
|
||||||
}
|
}
|
||||||
if (values.pid === undefined) {
|
if (values.pid === undefined) {
|
||||||
values.pid = '0'
|
values.pid = '0'
|
||||||
|
@ -210,16 +243,16 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
|
||||||
} else {
|
} else {
|
||||||
await addTask(values).then(response => {
|
await addTask(values).then(response => {
|
||||||
console.log('response', response)
|
console.log('response', response)
|
||||||
if (response.status.success) {
|
if (response.data.status.success) {
|
||||||
message.success("添加任务成功:" + response.data)
|
message.success(`添加计划${response.data.data.name}成功`)
|
||||||
// 树任务重新刷新
|
// 树任务重新刷新
|
||||||
// 四象限任务重新刷新
|
// 四象限任务重新刷新
|
||||||
// 如果可以直接更新列表而不请求。。。。。。
|
// 如果可以直接更新列表而不请求。。。。。。
|
||||||
console.log('props.reloadData?.()', props.reloadData)
|
console.log('props.reloadData?.()', props.reloadData)
|
||||||
|
result = (taskType!='1')
|
||||||
props.reloadData?.()
|
props.reloadData?.()
|
||||||
result = true
|
|
||||||
} else {
|
} else {
|
||||||
message.error(response.status.message)
|
message.error(response.data.status.message)
|
||||||
result = false
|
result = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -238,7 +271,7 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
|
||||||
width="sm"
|
width="sm"
|
||||||
name="taskType"
|
name="taskType"
|
||||||
label="任务类型"
|
label="任务类型"
|
||||||
initialValue='0'
|
initialValue={taskType}
|
||||||
disabled={editFormDisable}
|
disabled={editFormDisable}
|
||||||
onChange={(value: string, option) => {
|
onChange={(value: string, option) => {
|
||||||
setTaskType(value)
|
setTaskType(value)
|
||||||
|
@ -269,12 +302,12 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
|
||||||
pageSize: 1000,
|
pageSize: 1000,
|
||||||
pageNumber: 1,
|
pageNumber: 1,
|
||||||
data: [{code: 'pid', value: '0', operateType: '='},
|
data: [{code: 'pid', value: '0', operateType: '='},
|
||||||
// 如果父任务完成会导致父任务不展示
|
// 如果父任务完成会导致父任务不展示
|
||||||
// {
|
// {
|
||||||
// code: 'state',
|
// code: 'state',
|
||||||
// value: '8,9',
|
// value: '8,9',
|
||||||
// operateType: 'IN'
|
// operateType: 'IN'
|
||||||
// },
|
// },
|
||||||
{code: '', value: true, operateType: "TREE"}]
|
{code: '', value: true, operateType: "TREE"}]
|
||||||
}
|
}
|
||||||
)).then(result => childReduce(result.data.content))
|
)).then(result => childReduce(result.data.content))
|
||||||
|
@ -309,52 +342,48 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
|
||||||
/>
|
/>
|
||||||
</ProForm.Group>
|
</ProForm.Group>
|
||||||
<ProFormTextArea
|
<ProFormTextArea
|
||||||
// width="md"
|
width="xl"
|
||||||
name="description"
|
name="description"
|
||||||
label="任务描述"
|
label="任务描述"
|
||||||
// tooltip="最长为 24 位"
|
tooltip="最长255个字"
|
||||||
placeholder="请输入任务描述"
|
placeholder="请输入任务描述"
|
||||||
disabled={editFormDisable}
|
disabled={editFormDisable}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ProForm.Group>
|
<ProForm.Group>
|
||||||
<ProFormSelect
|
<ProFormSelect
|
||||||
request={async () => taskPriorityList.map(taskState => {
|
request={async () =>
|
||||||
return {
|
taskPriorityList.map
|
||||||
'label': taskState.name,
|
(
|
||||||
'value': taskState.code
|
taskState => {
|
||||||
}
|
return {'label': taskState.name, 'value': taskState.code}
|
||||||
})}
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
width="sm"
|
width="sm"
|
||||||
name="priority"
|
name="priority"
|
||||||
label="任务优先级"
|
label="任务优先级"
|
||||||
initialValue='3'
|
initialValue='3'
|
||||||
disabled={editFormDisable}
|
disabled={editFormDisable}
|
||||||
rules={[
|
rules={[{required: true, message: "请选择计划优先级"}]}
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: "请选择计划优先级"
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
/>
|
/>
|
||||||
<ProFormSelect
|
<ProFormSelect
|
||||||
width="sm"
|
width="sm"
|
||||||
options={taskStateList.map(taskState => {
|
options={taskStateList.map(taskState => {
|
||||||
return {
|
return {'label': taskState.name, 'value': taskState.code}
|
||||||
'label': taskState.name,
|
|
||||||
'value': taskState.code
|
|
||||||
}
|
|
||||||
})}
|
})}
|
||||||
name="state"
|
name="state"
|
||||||
label="任务状态"
|
label="任务状态"
|
||||||
initialValue='8'
|
initialValue='8'
|
||||||
disabled={editFormDisable}
|
disabled={editFormDisable}
|
||||||
rules={[
|
rules={
|
||||||
{
|
[
|
||||||
required: true,
|
{
|
||||||
message: "请选择计划状态"
|
required: true,
|
||||||
}
|
message: "请选择计划状态"
|
||||||
]}
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</ProForm.Group>
|
</ProForm.Group>
|
||||||
|
|
||||||
|
@ -378,4 +407,4 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
|
||||||
|
|
||||||
</ModalForm>
|
</ModalForm>
|
||||||
);
|
);
|
||||||
};
|
};
|
Loading…
Reference in New Issue