diff --git a/src/components/Loading.tsx b/src/components/Loading.tsx index ddb61faeac2b8658d957a3bdc30b2d62a7c1811b..22f9ab051590eb683b3f6e020f23a4df15676e5e 100644 --- a/src/components/Loading.tsx +++ b/src/components/Loading.tsx @@ -9,6 +9,7 @@ const LoadingWrapper = styled(Row)` bottom: 0; top: 0; background: #fff; + z-index: 100; padding-top: 300px; ` const Loading: React.FC = () => ( diff --git a/src/components/Public/StateTag.tsx b/src/components/Public/StateTag.tsx index 61010df86512839321e915a5e396e8c66723a672..9798ca1ff89f1a59eeb8643b05be11efd618b684 100644 --- a/src/components/Public/StateTag.tsx +++ b/src/components/Public/StateTag.tsx @@ -2,43 +2,69 @@ import React from "react" import { Tag } from "antd" type IProps = { - state: string + status: string } -const stateWordsMap = new Map([ - ["success", "新建"], - ["success1", "分析中"], - ["success2", "评审中"], - ["success3", "已评审"], - ["success4", "运行中"], - ["success5", "已完成"], -]) +export const stateWordsMap = new Map([ + ["analysing", "分析中"], + ["reviewing", "评审中"], + ["accepted", "已接受"], + ["refused", "已拒绝"], + + ["init", "初始化"], + ["waiting", "等待中"], + ["starting", "开始中"], + ["running", "运行中"], + ["stopping", "停止中"], + ["pedding", "待定中"], + + ["finish", "已完成"], + ["stopped", "已停止"], + ["pause", "暂停"], + ["skip", "跳过"], + ["cancel", "取消"], -const stateColorMap = new Map([ - ["success", "#1890FF"], - ["success1", "#FAAD15"], - ["success2", "#FAAD15"], - ["success3", "#22BC3D"], - ["success4", "#22BC3D"], - ["success5", "rgba(0,0,0,.3)"], + ["success", "成功"], + ["fail", "失败"], + ["error", "错误"], + ["ignore", "忽略"], + + ["online", "在线"], + ["offline", "下线"], + ["uninstalling", "卸载中"], + ["installing", "下载中"], ]) -const StateTag: React.FC = (props) => { - const { state } = props +export const planStatusMap = (state: any) => new Map([ + ["running", { "color": "rgba(24,144,255,1)", "background": "rgba(24,144,255,.1)" }], + ["reviewing", { "color": "rgba(24,144,255,1)", "background": "rgba(24,144,255,.1)" }], + + ["finish", { "color": "rgba(34,188,61,1)", "background": "rgba(34,188,61,.1)" }], + ["accepted", { "color": "rgba(34,188,61,1)", "background": "rgba(34,188,61,.1)" }], + ["success", { "color": "rgba(34,188,61,1)", "background": "rgba(34,188,61,.1)" }], + + ["analysing", { "color": "rgba(250,173,21,1)", "background": "rgba(250,173,21,.1)" }], + ["pedding", { "color": "rgba(250,173,21,1)", "background": "rgba(250,173,21,.1)" }], + + ["refused", { "color": "rgba(255,77,79,1)", "background": "rgba(255,77,79,.1)" }], + ["fail", { "color": "rgba(255,77,79,1)", "background": "rgba(255,77,79,.1)" }], + ["error", { "color": "rgba(255,77,79,1)", "background": "rgba(255,77,79,.1)" }], +]).get(state) || { "color": "rgba(0,0,0,0.45)", "background": "rgba(0,0,0,0.03)" } + +export const StateTag: React.FC = (props) => { + const { status } = props return ( - {stateWordsMap.get(state)} + {stateWordsMap.get(status)} ) -} - -export default StateTag \ No newline at end of file +} \ No newline at end of file diff --git a/src/components/RichTextEditor/index.tsx b/src/components/RichTextEditor/index.tsx index e70aadcf7ba31534dedd785e339d8d098fb256e4..ed995e515e6e0a4585e751f5abdfcd969605555f 100644 --- a/src/components/RichTextEditor/index.tsx +++ b/src/components/RichTextEditor/index.tsx @@ -30,6 +30,7 @@ const RichTextEditor: React.FC = (props) => { ...config, placeholder: "请输入内容", MENU_CONF: { + }, onCreated(vm) { const tb = createToolbar({ diff --git a/src/pages/Plan/CreatePage.tsx b/src/pages/Plan/CreatePage.tsx new file mode 100644 index 0000000000000000000000000000000000000000..747431a643916d100f2c3306eeefd9ed27e5ef97 --- /dev/null +++ b/src/pages/Plan/CreatePage.tsx @@ -0,0 +1,123 @@ +import React from "react" +import { Table, Space, Typography, Row, Button, Col, Spin, Form, message, Input, Select } from "antd" +import { createTestPlan, queryTestPlanList, updateTestPlanDetail } from "./services" +import Loading from "@/components/Loading" +import { history, request, useParams, useRequest } from "umi" +import RichTextEditor from "@/components/RichTextEditor" + +import SuiteTable from "@/pages/Plan/components/ContentTable/Suite.table" +import TaskTable from "@/pages/Plan/components/ContentTable/Task.table" +import { CustomForm } from "@/components/CustomStyled" +import { usePlanProvider } from "./hooks" +/** + * + * 测试方案 + * + */ + +type IProps = { + [k: string]: any; +} + +const TestPlan: React.FC = (props) => { + const { refresh } = usePlanProvider() + const { plan_id } = useParams() as any + const { source, onOk } = props + const [form] = Form.useForm() + console.log(props, plan_id) + + React.useEffect(() => { + if (source && JSON.stringify(source) !== "{}") { + const { req_id, title } = source + form.setFieldsValue({ req_id, title }) + } + }, [source]) + + const [baseData, setBaseData] = React.useState({}) + + const { data: requirement, run } = useRequest(() => request(`/api/requirement`), { initialData: [], manual: true }) + + React.useEffect(() => { + run() + }, []) + + const handleSave = () => { + form.validateFields() + .then(async (values) => { + const params = { ...baseData, ...values, reviewers: "xxxx" } + const isEditPage = plan_id && source + const { data, code, msg } = isEditPage ? + await updateTestPlanDetail(plan_id, params) : + await createTestPlan(params) + if (code !== 200) { + message.error(msg) + return + } + if (isEditPage) { + onOk() + refresh() + message.success("操作成功") + } + else + history.push(`/plan/${data.id}`) + }) + } + + return ( +
+ + + 新建方案 + + + 基础信息 + + + + + + - - - - - - - - - - - - - 描述 -
- -
-
-
-
- ) -} - -export default PlanRighttEditContent \ No newline at end of file diff --git a/src/pages/Plan/components/RightContent/index.tsx b/src/pages/Plan/components/RightContent/index.tsx index d8e60f8b71149f729d7eacfdf2b791436313b009..895a4051d045cf05c23efaaea3b9e5507947dfe3 100644 --- a/src/pages/Plan/components/RightContent/index.tsx +++ b/src/pages/Plan/components/RightContent/index.tsx @@ -1,54 +1,156 @@ -import React from "react"; -import { Space, Row, Typography, Button, Form, Input, Select, Card } from "antd" +import React, { useState } from "react"; +import { Space, Row, Typography, Button, Empty, Menu, Dropdown, Avatar, Divider, Col, message } from "antd" import RichTextEditor from "@/components/RichTextEditor"; +import { history, useParams, useRequest } from "umi"; +import { deleteTestPlan, queryTestPlanDetail } from "../../services"; +import Loading from "@/components/Loading"; +import { createEditor } from "@wangeditor/editor" +import SuiteTable from "@/pages/Plan/components/ContentTable/Suite.table" +import TaskTable from "@/pages/Plan/components/ContentTable/Task.table" +import styled from "styled-components" +import Logo from "@/assets/logo.png" +import { ReactComponent as Priority } from "@/assets/case/priority.svg" +import { stateWordsMap } from "@/components/Public/StateTag" +import { MoreOutlined } from "@ant-design/icons" +import CreatePage from "@/pages/Plan/CreatePage" type IProps = { [k: string]: any; } +const PriorityAvatar = styled.div` + width: 32px; + height: 32px; + display: flex; + justify-content: center; + align-items: center; + border-radius: 50%; + overflow: hidden; +` + const PlanRightContent: React.FC = () => { + const { plan_id } = useParams() as any + + const [edit, setEdit] = useState(false) + const { data, run, refresh } = useRequest(queryTestPlanDetail, { manual: true, initialData: null }) + + React.useEffect(() => { + if (plan_id) + run(plan_id) + }, [plan_id]) + + const handleMenuClick = (e: any) => { + switch (e.key) { + case "delete": return handleDelete() + } + return + } + + const handleDelete = async () => { + const { code, msg } = await deleteTestPlan(plan_id) + if (code !== 200) return message.error(msg) + history.push(`/plan`) + message.success("操作成功!") + } + + const handleEditOk = () => { + setEdit(false) + refresh() + } + + if (edit) + return + + if (plan_id && !data) return + + if (!plan_id) return ( + + + + ) - const [form] = Form.useForm() return ( - - - - - 基础信息 - - -
- - - - - - - -
-
- - - - 描述 - -
- -
-
- - 选择用例}> - - - - 选择任务}> - - -
+ + + + + 创建于 + {data.gmt_created} + + + 更新于 + {data.gmt_modified} + + + + + + + 删除 + + + } + > + + + + + + + + + {data.title} + + + + + + + + {data?.owner} + 负责人 + + + + + + + + + + {stateWordsMap.get(data?.status)} + 状态 + + + + + + + + + 基础信息 + + + + 测试需求 + {data.req_id} + + + + + + 描述 + +
+ + + ) } diff --git a/src/pages/Plan/components/SelectModal/Suite.selet.tsx b/src/pages/Plan/components/SelectModal/Suite.selet.tsx index 67814caa193495b078fe2450b34e5e53233ffa97..1a045d1f055f0667fffe8654571085e2d7fbb05a 100644 --- a/src/pages/Plan/components/SelectModal/Suite.selet.tsx +++ b/src/pages/Plan/components/SelectModal/Suite.selet.tsx @@ -29,13 +29,12 @@ const ReactComponent: React.ForwardRefRenderFunction = (props, re const [visible, setVisible] = React.useState(false) const [loading, setLoading] = React.useState(false) - const [source, setSource] = React.useState(undefined) React.useImperativeHandle(ref, () => ({ show(_: any) { - setSource(_) + setSelectedKeys(_) + setCheckAll(_.length === cases.length) setVisible(true) - form.setFieldsValue(_) } })) @@ -57,12 +56,9 @@ const ReactComponent: React.ForwardRefRenderFunction = (props, re setCheckAll(list.length === allCaseId.length); } - const [form] = Form.useForm() - const handleCancel = () => { setVisible(false) setLoading(false) - setSource(undefined) setSelectedKeys([]) setIndeterminate(false) setCheckAll(false) @@ -81,15 +77,19 @@ const ReactComponent: React.ForwardRefRenderFunction = (props, re setSelectedKeys([]) } + const handleKeyup = (e: any) => { + + } + return ( - {`共${allCaseId.length}条 已选中${selectedKeys.length}条`} + {`共${allCaseId.length}条`} @@ -100,7 +100,11 @@ const ReactComponent: React.ForwardRefRenderFunction = (props, re onCancel={handleCancel} > - +
= (props, re const [visible, setVisible] = React.useState(false) const [loading, setLoading] = React.useState(false) - const [source, setSource] = React.useState(undefined) const [selectedKeys, setSelectedKeys] = React.useState([]) const { data: taskList, loading: taskLoading } = useRequest(queryTaskList, { initialData: [] }) React.useImperativeHandle(ref, () => ({ show(_: any) { - setSource(_) + setSelectedKeys(_) setVisible(true) - form.setFieldsValue(_) } })) - const [form] = Form.useForm() - const handleCancel = () => { setVisible(false) setLoading(false) - setSource(undefined) + setSelectedKeys([]) } const handleOk = async () => { if (loading) return setLoading(true) - onOk([]) + onOk(taskList.filter((i: any) => selectedKeys.includes(i.id))) handleCancel() } diff --git a/src/pages/Plan/index.tsx b/src/pages/Plan/index.tsx index 1e4887637c992b83a9bd610f6b9318faa3acd868..8698c9d280ffaed5e97e683e620b798f2f22ec3d 100644 --- a/src/pages/Plan/index.tsx +++ b/src/pages/Plan/index.tsx @@ -1,20 +1,16 @@ import React from "react" -import { Table, Space, Typography, Row, Button, Col, Spin, Form, message, Input, Select } from "antd" -import { createTestPlan, queryTestPlanList } from "./services" -import { useRequest } from "umi" -import AddModal from "./components/AddModal" +import { Row, Spin, } from "antd" +import { queryTestPlanList } from "./services" import LeftList from "./components/LeftList" -import RightContent from "./components/RightContent" -import EditContent from "./components/RightContent/EditContent" +// import EditContent from "./components/RightContent/EditContent" import { Provider as PlanPageProvider } from "./hooks" import Loading from "@/components/Loading" -import { history, request, useParams } from "umi" -import RichTextEditor from "@/components/RichTextEditor" +import { history, useParams, useRequest } from "umi" + +const CreatePage = React.lazy(() => import("@/pages/Plan/CreatePage")) +const RightContent = React.lazy(() => import("@/pages/Plan/components/RightContent")) -import SuiteTable from "@/pages/Plan/components/ContentTable/Suite.table" -import TaskTable from "@/pages/Plan/components/ContentTable/Task.table" -import { CustomForm } from "@/components/CustomStyled" /** * * 测试方案 @@ -26,94 +22,41 @@ type IProps = { } const TestPlan: React.FC = (props) => { - const [form] = Form.useForm() - const { data: requirement } = useRequest(() => request(`/api/requirement`), { initialData: [] }) - - const handleSave = () => { - form.validateFields() - .then(async (values) => { - const { code, msg } = await createTestPlan(values) - if (code !== 200) { - message.error(msg) - return - } - }) - } - - const requirementList = React.useMemo(() => { - if (requirement) - return requirement.map((i: any) => ({ label: i.title, value: i.id })) - return [] - }, [requirement]) - - return ( -
- - - 新建方案 - - - 基础信息 - - - - - -