PreTask.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import { Button, List, Popover, Switch, Tag, Typography } from "antd";
  2. import type { ITaskData, ITaskListResponse } from "../../api/task";
  3. import { get } from "../../request";
  4. import { useEffect, useState } from "react";
  5. import { ArrowLeftOutlined, ArrowRightOutlined } from "@ant-design/icons";
  6. import type { TRelation } from "./TaskEditButton";
  7. const { Text } = Typography;
  8. interface IProTaskListProps {
  9. task?: ITaskData;
  10. type: TRelation;
  11. onClick?: (data?: ITaskData | null) => void;
  12. onClose?: () => void;
  13. onChange?: (data: ITaskData, has: boolean) => void;
  14. }
  15. const ProTaskList = ({
  16. task,
  17. type,
  18. onClick,
  19. onClose,
  20. onChange,
  21. }: IProTaskListProps) => {
  22. const [res, setRes] = useState<ITaskData[]>();
  23. useEffect(() => {
  24. const url = `/v2/task?view=project&project_id=${task?.project_id}`;
  25. console.info("api request", url);
  26. get<ITaskListResponse>(url).then((json) => {
  27. console.info("project api response", json);
  28. const res = json.data.rows;
  29. setRes(res);
  30. });
  31. }, [task?.project_id]);
  32. return (
  33. <List
  34. header={
  35. <div>
  36. <div style={{ display: "flex", justifyContent: "space-between" }}>
  37. <Text strong>{type === "pre" ? "前置任务" : "后置任务"}</Text>
  38. <div>
  39. <Button type="link" onClick={onClose}>
  40. 关闭
  41. </Button>
  42. </div>
  43. </div>
  44. </div>
  45. }
  46. footer={false}
  47. dataSource={res}
  48. renderItem={(item) => {
  49. let checked = false;
  50. if (type === "pre") {
  51. checked =
  52. task?.pre_task?.find((value) => value.id === item.id) !== undefined;
  53. } else {
  54. checked =
  55. task?.next_task?.find((value) => value.id === item.id) !==
  56. undefined;
  57. }
  58. return (
  59. <List.Item
  60. actions={[
  61. <Switch
  62. size="small"
  63. checked={checked}
  64. onChange={(checked) => {
  65. onChange && onChange(item, checked);
  66. }}
  67. />,
  68. ]}
  69. onClick={() => {
  70. onClick && onClick(item);
  71. }}
  72. >
  73. {item.title}
  74. </List.Item>
  75. );
  76. }}
  77. />
  78. );
  79. };
  80. interface IWidget {
  81. task?: ITaskData;
  82. open?: boolean;
  83. type: TRelation;
  84. onClick?: (data?: ITaskData | null) => void;
  85. onTagClick?: () => void;
  86. onClose?: () => void;
  87. onChange?: (data: ITaskData, has: boolean) => void;
  88. }
  89. const PreTask = ({
  90. task,
  91. type,
  92. open = false,
  93. onClick,
  94. onClose,
  95. onTagClick,
  96. onChange,
  97. }: IWidget) => {
  98. const preTaskShow = open || task?.pre_task;
  99. const nextTaskShow = open || task?.next_task;
  100. let tag = <></>;
  101. if (preTaskShow && type === "pre") {
  102. tag = (
  103. <Tag color="warning" icon={<ArrowLeftOutlined />} onClick={onTagClick}>
  104. {task?.pre_task ? `${task?.pre_task?.length} 个前置任务` : ""}
  105. </Tag>
  106. );
  107. } else if (nextTaskShow && type === "next") {
  108. tag = (
  109. <Tag color="warning" icon={<ArrowRightOutlined />} onClick={onTagClick}>
  110. {task?.next_task ? `阻塞 ${task?.next_task?.length} 个任务` : ""}
  111. </Tag>
  112. );
  113. }
  114. return (
  115. <Popover
  116. trigger="click"
  117. open={open}
  118. content={
  119. <div style={{ width: 400 }}>
  120. <ProTaskList
  121. type={type}
  122. task={task}
  123. onClick={onClick}
  124. onClose={onClose}
  125. onChange={onChange}
  126. />
  127. </div>
  128. }
  129. >
  130. {tag}
  131. </Popover>
  132. );
  133. };
  134. export default PreTask;