TaskReader.tsx 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import { useEffect, useState } from "react";
  2. import { Divider, Space, Tag, Typography, message } from "antd";
  3. import { CodeSandboxOutlined } from "@ant-design/icons";
  4. import { ITaskData, ITaskResponse, ITaskUpdateRequest } from "../api/task";
  5. import { get, patch } from "../../request";
  6. import MdView from "../template/MdView";
  7. import User from "../auth/User";
  8. import TimeShow from "../general/TimeShow";
  9. import TaskEditButton, { TRelation } from "./TaskEditButton";
  10. import PreTask from "./PreTask";
  11. import Like from "../like/Like";
  12. import Assignees from "./Assignees";
  13. const { Title } = Typography;
  14. export const Milestone = ({ task }: { task?: ITaskData }) => {
  15. return task?.is_milestone ? (
  16. <Tag icon={<CodeSandboxOutlined />} color="error">
  17. 里程碑
  18. </Tag>
  19. ) : null;
  20. };
  21. export const Status = ({ task }: { task?: ITaskData }) => {
  22. return task?.status === "pending" ? (
  23. <Tag color="default">未发布</Tag>
  24. ) : task?.status === "published" ? (
  25. <Tag color="warning">待领取</Tag>
  26. ) : task?.status === "running" ? (
  27. <Tag color="processing">进行中</Tag>
  28. ) : task?.status === "done" ? (
  29. <Tag color="success">已完成</Tag>
  30. ) : task?.status === "restarted" ? (
  31. <Tag color="error">已重启</Tag>
  32. ) : null;
  33. };
  34. interface IWidget {
  35. taskId?: string;
  36. onChange?: (data: ITaskData[]) => void;
  37. onEdit?: () => void;
  38. }
  39. const TaskReader = ({ taskId, onChange, onEdit }: IWidget) => {
  40. const [openPreTask, setOpenPreTask] = useState(false);
  41. const [openNextTask, setOpenNextTask] = useState(false);
  42. const [task, setTask] = useState<ITaskData>();
  43. useEffect(() => {
  44. const url = `/v2/task/${taskId}`;
  45. console.info("task api request", url);
  46. get<ITaskResponse>(url).then((json) => {
  47. console.info("task api response", json);
  48. if (json.ok) {
  49. setTask(json.data);
  50. }
  51. });
  52. }, [taskId]);
  53. const updatePreTask = (type: TRelation, data?: ITaskData | null) => {
  54. if (!taskId || !data) {
  55. return;
  56. }
  57. let setting: ITaskUpdateRequest = {
  58. id: taskId,
  59. studio_name: "",
  60. };
  61. if (type === "pre") {
  62. const hasPre = task?.pre_task?.find((value) => value.id === data.id);
  63. if (hasPre) {
  64. setting.pre_task_id = task?.pre_task
  65. ?.filter((value) => value.id !== data.id)
  66. .map((item) => item.id)
  67. .join();
  68. } else {
  69. const newRelation = task?.pre_task
  70. ? [...task.pre_task.map((item) => item.id), data.id]
  71. : [data.id];
  72. setting.pre_task_id = newRelation.join();
  73. }
  74. } else if (type === "next") {
  75. const hasPre = task?.next_task?.find((value) => value.id === data.id);
  76. if (hasPre) {
  77. setting.next_task_id = task?.next_task
  78. ?.filter((value) => value.id !== data.id)
  79. .map((item) => item.id)
  80. .join();
  81. } else {
  82. const newRelation = task?.next_task
  83. ? [...task.next_task.map((item) => item.id), data.id]
  84. : [data.id];
  85. setting.next_task_id = newRelation.join();
  86. }
  87. }
  88. const url = `/v2/task/${setting.id}`;
  89. console.info("api request", url, setting);
  90. patch<ITaskUpdateRequest, ITaskResponse>(url, setting).then((json) => {
  91. console.info("api response", json);
  92. if (json.ok) {
  93. message.success("Success");
  94. setTask(json.data);
  95. onChange && onChange([json.data]);
  96. } else {
  97. message.error(json.message);
  98. }
  99. });
  100. };
  101. return (
  102. <div>
  103. <div style={{ display: "flex", justifyContent: "space-between" }}>
  104. <Space>
  105. <Status task={task} />
  106. <Milestone task={task} />
  107. <PreTask
  108. task={task}
  109. open={openPreTask}
  110. type="pre"
  111. onClick={(data) => {
  112. updatePreTask("pre", data);
  113. setOpenPreTask(false);
  114. }}
  115. onTagClick={() => setOpenPreTask(true)}
  116. onClose={() => setOpenPreTask(false)}
  117. />
  118. <PreTask
  119. task={task}
  120. open={openNextTask}
  121. type="next"
  122. onClick={(data) => {
  123. updatePreTask("next", data);
  124. setOpenNextTask(false);
  125. }}
  126. onClose={() => setOpenNextTask(false)}
  127. onTagClick={() => setOpenNextTask(true)}
  128. />
  129. </Space>
  130. <div>
  131. <TaskEditButton
  132. task={task}
  133. onChange={(tasks: ITaskData[]) => {
  134. setTask(tasks.find((value) => value.id === taskId));
  135. onChange && onChange(tasks);
  136. }}
  137. onEdit={onEdit}
  138. onPreTask={(type: TRelation) => {
  139. if (type === "pre") {
  140. setOpenPreTask(true);
  141. } else if (type === "next") {
  142. setOpenNextTask(true);
  143. }
  144. }}
  145. />
  146. </div>
  147. </div>
  148. <Title>{task?.title}</Title>
  149. <div>
  150. <div>
  151. <Space>
  152. <User {...task?.editor} />
  153. <TimeShow updatedAt={task?.updated_at} />
  154. <Like resId={task?.id} resType="task" />
  155. </Space>
  156. </div>
  157. <div>
  158. <Assignees task={task} showIcon={true} onChange={onChange} />
  159. </div>
  160. </div>
  161. <Divider />
  162. <MdView html={task?.html} />
  163. </div>
  164. );
  165. };
  166. export default TaskReader;