diff --git a/abc.json b/abc.json index 06a1bce22a227ad9e820ea812cfe2c7a41ffc66d..320de5e96508fad2aafadeed7fa455bb8e06f3e8 100644 --- a/abc.json +++ b/abc.json @@ -4,10 +4,10 @@ "command": { "cmd": [ "pnpm install", - "pnpm build", + "pnpm build:tone", "mv ./dist $BUILD_DEST" ] } }, - "nodeVersion": 16 -} \ No newline at end of file + "nodeVersion": 20 +} diff --git a/package.json b/package.json index 24b4a6987a1598549c00a85f62db8bc8f30b477c..44bb0a4a5e04095b69adec66ef42d96e87f26253 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,15 @@ { "name": "tone-front", - "version": "1.18.0", + "version": "1.19.0", "private": true, "description": "Tone front", "scripts": { - "start": "cross-env BUILD_APP_ENV=\"opensource\" PORT=8888 umi dev", - "build": "cross-env BUILD_APP_ENV=\"opensource\" umi build", - "start:openanolis": "cross-env PORT=8888 BUILD_APP_ENV=\"openanolis\" umi dev", - "build:openanolis": "cross-env BUILD_APP_ENV=\"openanolis\" umi build", - "start:tone": "cross-env BUILD_APP_ENV= PORT=8888 umi dev", - "build:tone": "cross-env BUILD_APP_ENV= PORT=8888 umi build", + "start": "cross-env NODE_OPTIONS=--openssl-legacy-provider BUILD_APP_ENV=\"opensource\" PORT=8888 umi dev", + "build": "cross-env NODE_OPTIONS=--openssl-legacy-provider BUILD_APP_ENV=\"opensource\" umi build", + "start:openanolis": "cross-env NODE_OPTIONS=--openssl-legacy-provider PORT=8888 BUILD_APP_ENV=\"openanolis\" umi dev", + "build:openanolis": "cross-env NODE_OPTIONS=--openssl-legacy-provider BUILD_APP_ENV=\"openanolis\" umi build", + "start:tone": "cross-env NODE_OPTIONS=--openssl-legacy-provider BUILD_APP_ENV= PORT=8888 umi dev", + "build:tone": "cross-env NODE_OPTIONS=--openssl-legacy-provider BUILD_APP_ENV= PORT=8888 umi build", "analyze": "cross-env ANALYZE=1 umi build", "deploy": "npm run site && npm run gh-pages", "dev": "npm run start:dev", diff --git a/src/app.tsx b/src/app.tsx index 3c38d61aa59b3f5db16433a190baf3c2bef82895..8da4efa50a88da547fe9ac63e242c76ea8123a45 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -112,7 +112,7 @@ export async function getInitialState(): Promise { redirectErrorPage(401); return baseAppState; } - const ws: any = await enterWsAndGetList(ws_id); + const ws: any = await enterWsAndGetList(ws_id) || {} if (ws?.first_entry) { history.push(`/ws/${ws_id}/workspace/initSuccess`); } diff --git a/src/components/Header/components/HeaderDropdown.tsx b/src/components/Header/components/HeaderDropdown.tsx index 40e90da7fef1432efd06b9ee5069ebdb8bd3732e..9bf4a31a86cca9d2620f99ea3ee22eb19bdba956 100644 --- a/src/components/Header/components/HeaderDropdown.tsx +++ b/src/components/Header/components/HeaderDropdown.tsx @@ -93,7 +93,7 @@ export const HearderDropdown: React.FC = (props) => { const current = React.useMemo(() => { if (!wsList) return {} - const [workspace] = wsList?.data?.filter(({ id }: any) => id === ws_id) + const [workspace] = (wsList?.data || [])?.filter(({ id }: any) => id === ws_id) // wsList?.data?.filter(({ id }: any) => id === ws_id) if (workspace) return workspace return {} }, [wsList, ws_id]) diff --git a/src/components/Header/components/JobModal.tsx b/src/components/Header/components/JobModal.tsx index a159523b9f8deb4d9f19da208b91609ff7caaaa9..ac027f7cdc2e0303e8a6b17ca89161f401e747d9 100644 --- a/src/components/Header/components/JobModal.tsx +++ b/src/components/Header/components/JobModal.tsx @@ -15,7 +15,7 @@ const JobTemplateModal: React.FC> = (props) => { const dataSourceCopy = props.getData(jobTemplates) return ( - + = ({ confirm, onConfirm, value, page_size, mode = 'multiple' }) => { +const FilterRadio: React.FC = ({ confirm, onConfirm, value, page_size, mode = 'multiple', ws_id: selectedWsId }) => { const { ws_id } = useParams() as any const [user, setUser] = useState([]) const [keyword, setKeyword] = useState() @@ -19,14 +19,14 @@ const FilterRadio: React.FC = ({ confirm, onConfirm, value, page_size, mode if (keyword && keyword == param) return setKeyword(param) setFetching(true) - const { data } = await queryMember({ ws_id, keyword: param, page_size: page_size || 10, page_num: 1 }) + const { data } = await queryMember({ ws_id: selectedWsId || ws_id, keyword: param, page_size: page_size || 10, page_num: 1 }) setUser(Array.isArray(data) ? data : []) setFetching(false) } useEffect(() => { handleSearch() - }, []); + }, [selectedWsId]); const handleCancleSel = () => { handleSearch() diff --git a/src/pages/RefenerceDetail/index.tsx b/src/pages/RefenerceDetail/index.tsx index 86484b4039367129afdbbb81d6b18ce09cd1848e..e37263fee4af5425b4379f33c4e77e7cf336e355 100644 --- a/src/pages/RefenerceDetail/index.tsx +++ b/src/pages/RefenerceDetail/index.tsx @@ -47,7 +47,7 @@ const Wapper = styled.div` const { Panel } = Collapse; const Refenerce = (props: any) => { const { type: $type } = useParams() as any - const { query: { pk } } = useLocation() as any + const { query: { pk, case_id_list } } = useLocation() as any const [JobTotal, setJobTotal] = useState(0) const [JobData, setJobData] = useState([]) const [TempTotal, setTempTotal] = useState(0) @@ -89,17 +89,28 @@ const Refenerce = (props: any) => { } const queryListData = async () => { - const { id } = source + const { id, visible_range, optionType } = source setLoading(true) const JobObj: any = { flag: 'job', ...params } const TempObj: any = { flag: 'template', ...tempParams } - if ($type === 'suite') { + // 同步操作参数 + if (case_id_list) { + JobObj.case_id_list = case_id_list + TempObj.case_id_list = case_id_list + } else if ($type === 'suite') { JobObj.suite_id = id TempObj.suite_id = id } else { JobObj.case_id_list = id TempObj.case_id_list = id } + + // 编辑操作传 visible_range; + // 同步、删除操作不传 visible_range; + if (optionType === "edit") { + JobObj.visible_range = visible_range + TempObj.visible_range = visible_range + } const { total, data, code, msg } = await queryConfirm(JobObj) if (code !== 200) { requestCodeMessage(code, msg) diff --git a/src/pages/SystemConf/TestSuite/BasicTest/components/AddSuiteTest.tsx b/src/pages/SystemConf/TestSuite/BasicTest/components/AddSuiteTest.tsx index 462c9e8bf5a5250358e7ae8b6b9575164cc370fb..920157ed5a85429ec92fa023b77d561b586a61b8 100644 --- a/src/pages/SystemConf/TestSuite/BasicTest/components/AddSuiteTest.tsx +++ b/src/pages/SystemConf/TestSuite/BasicTest/components/AddSuiteTest.tsx @@ -14,7 +14,7 @@ import DeleteTips from './DeleteTips'; /** * @module 系统级 - * @description 新增、编辑suite级 + * @description 新增、编辑suite */ export default forwardRef( ({ onOk, wsList }: any, ref: any) => { @@ -110,7 +110,7 @@ export default forwardRef( if (s !== t) { setDisable(true) const { code } = await queryConfirm({ flag: 'pass', suite_id: dataSource.id, visible_range: s }) - if (code === 200) return delTip.current?.show({ ...dataSource, path: 'visible_range', visible_range: s }) + if (code === 200) return delTip.current?.show({ ...dataSource, path: 'visible_range', visible_range: s, optionType: 'edit' }) } } handleEditOK(val) diff --git a/src/pages/SystemConf/TestSuite/BasicTest/components/DeleteTips.tsx b/src/pages/SystemConf/TestSuite/BasicTest/components/DeleteTips.tsx index d5c3d4ad964b399db5da11eab276557bcb6231a8..caa2f54a5a8da5e66b03e0a8cec44d688b2ccffb 100644 --- a/src/pages/SystemConf/TestSuite/BasicTest/components/DeleteTips.tsx +++ b/src/pages/SystemConf/TestSuite/BasicTest/components/DeleteTips.tsx @@ -34,8 +34,7 @@ const DeleteTip: React.ForwardRefRenderFunction = (props, ref) => const handleOpenRef = async () => { if (!setting) return - const { name, id } = setting - const pk = await saveRefenerceData({ name, id }) + const pk = await saveRefenerceData(setting) if (pk) window.open(`${basePath || "/refenerce/suite/"}?pk=${pk}`) } @@ -47,11 +46,11 @@ const DeleteTip: React.ForwardRefRenderFunction = (props, ref) => open={visible} onCancel={hanldeCancel} footer={[ - , + // , diff --git a/src/pages/SystemConf/TestSuite/BasicTest/components/SynchronizeModal.tsx b/src/pages/SystemConf/TestSuite/BasicTest/components/SynchronizeModal.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d23d422d337abf78d516ab778a3f84d5fbe6f708 --- /dev/null +++ b/src/pages/SystemConf/TestSuite/BasicTest/components/SynchronizeModal.tsx @@ -0,0 +1,76 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions */ +import React from "react" +import { Modal, Button, Typography, Space } from "antd" +import { FormattedMessage, useIntl } from "umi" +import { ExclamationCircleOutlined } from "@ant-design/icons" +import { saveRefenerceData } from "@/utils/utils" + +const SynchronizeModal = (props: any, ref: any) => { + const { formatMessage } = useIntl() + const [visible, setVisible] = React.useState(false) + const [setting, setSetting] = React.useState() + + React.useImperativeHandle(ref, () => ({ + show(_: any) { + _ && setSetting(_) + setVisible(true) + } + })) + + const handleOk = () => { + props?.onOk(setting) + setVisible(false) + setSetting(null) + } + + const handleCancel = () => { + setVisible(false) + setSetting(null) + } + + const handleOpenRef = async () => { + if (!setting) return + const { name, id, delete_temp_case_id_list } = setting + const case_id_list = delete_temp_case_id_list?.join() + const pk = await saveRefenerceData({ name, id }) + if (pk) window.open(`${props.basePath || "/refenerce/suite/"}?pk=${pk}${case_id_list? `&case_id_list=${case_id_list}`: ''}`) + } + + return ( + } + centered={true} + open={visible} + onCancel={handleCancel} + footer={[ + // , + + ]} + width={600} + > + + + + + {setting?.msg || formatMessage({ id: 'TestSuite.suite.delete.warning' }, { data: setting?.name })} + + + + {setting?.id && setting?.name && + + + + } + + + ) +} + +export default React.forwardRef(SynchronizeModal) \ No newline at end of file diff --git a/src/pages/SystemConf/TestSuite/BasicTest/index.tsx b/src/pages/SystemConf/TestSuite/BasicTest/index.tsx index efd4563c37d9f0545d90cf677924690cc5c32012..e9f5ea6a5973253601241b7af318568595c9b926 100644 --- a/src/pages/SystemConf/TestSuite/BasicTest/index.tsx +++ b/src/pages/SystemConf/TestSuite/BasicTest/index.tsx @@ -23,7 +23,7 @@ import ConfEditDrawer from './components/CaseTable/ConfEditDrawer' import lodash from 'lodash' import { queryConfirm } from '@/pages/WorkSpace/JobTypeManage/services'; import { useSuiteProvider } from '../hooks'; - +import SynchronizeModal from './components/SynchronizeModal'; import DeleteTips from "./components/DeleteTips" import DeleteDefault from "./components/DeleteDefault" import MetricBatchDelete from './components/MetricTable/MetricBatchDelete'; @@ -49,7 +49,6 @@ const SuiteManagement: React.ForwardRefRenderFunction = (props const [pageParams, setPageParams] = useState(DEFAULT_PAGE_PARAMS) const [loading, setLoading] = useState(true) - const [sync, setSync] = useState(false) const [expandKey, setExpandKey] = useState([]) const [selectedRowKeys, setSelectedRowKeys] = useState([]) const [selectedRow, setSelectedRow] = useState([]) @@ -65,6 +64,7 @@ const SuiteManagement: React.ForwardRefRenderFunction = (props { id: 0, name: formatMessage({ id: 'operation.no' }) }, ] + const synchronizeRef: any = useRef(null) const confDrawer: any = useRef(null) const suiteEditDrawer: any = useRef(null) const deleteTipsRef = React.useRef(null) @@ -130,8 +130,8 @@ const SuiteManagement: React.ForwardRefRenderFunction = (props for (let i = 0; i < arr.length; i++) newArr.push(Number.parseInt(arr[i])) row.domain_list_str = newArr domainList.forEach((item: any) => { if (item.name == row.domain) row.domain = item.id }) - - suiteEditDrawer.current.show('edit', row) // 编辑Test Suite + // 编辑Test Suite + suiteEditDrawer.current.show('edit', row) } const onDesSubmit = async ({ doc, id }: any) => { @@ -151,9 +151,14 @@ const SuiteManagement: React.ForwardRefRenderFunction = (props const deleteOuter = async (row: any) => { const { code } = await queryConfirm({ flag: 'pass', suite_id: row.id }) - if (code === 200) - return deleteTipsRef.current?.show(row) - defaultDeleteRef.current?.show(row) + // 判断是否有引用 + if (code === 200) { + // 有引用 + deleteTipsRef.current?.show(row) + } else { + // 无引用 + defaultDeleteRef.current?.show(row) + } } const remOuter = async (row: any) => { @@ -168,20 +173,41 @@ const SuiteManagement: React.ForwardRefRenderFunction = (props getList() } - const synchro = async (row: any) => { - setSync(true) + // 同步判断弹窗: 201有引用 + const onSynchronize = async (row: any) => { + props.setSynchronizeLoading(true) const hide = message.loading({ content: formatMessage({ id: 'operation.synchronizing' }), duration: 0 }) - const { code, msg } = await syncSuite(row.id) - setSync(false) + const { code, data, msg } = await syncSuite(row.id).catch(()=> props.setSynchronizeLoading(false)) + props.setSynchronizeLoading(false) hide() - if (code !== 200) { - message.warning(`${formatMessage({ id: 'request.synchronize.failed' })},${msg}`) - return + // 判断无引用 + if (code === 200) { + message.success(formatMessage({ id: 'request.synchronize.success' })) + getList() + setAsyncTime(new Date().getTime()) + } else if (code === 201) { + // 201 有引用 + const { id, name } = row + synchronizeRef.current?.show({ id, name, ...data }) + } else { + synchronizeRef.current?.show({ code, msg }) } - message.success(formatMessage({ id: 'request.synchronize.success' })) - getList() - setAsyncTime(new Date().getTime()) } + + // const synchro = async (row: any) => { + // setSync(true) + // const hide = message.loading({ content: formatMessage({ id: 'operation.synchronizing' }), duration: 0 }) + // const { code, msg } = await syncSuite(row.id) + // setSync(false) + // hide() + // if (code !== 200) { + // message.warning(`${formatMessage({ id: 'request.synchronize.failed' })},${msg}`) + // return + // } + // message.success(formatMessage({ id: 'request.synchronize.success' })) + // getList() + // setAsyncTime(new Date().getTime()) + // } const wsMap = React.useMemo(() => { return (wsList || []).reduce((pre: any, cur: any) => { @@ -394,7 +420,7 @@ const SuiteManagement: React.ForwardRefRenderFunction = (props fixed: 'right', render: (_, row) => ( - synchro(row)}> + onSynchronize(row)}> editOuter(row)}> @@ -533,12 +559,8 @@ const SuiteManagement: React.ForwardRefRenderFunction = (props } - {/* 同步遮罩 */} - + {/* 同步 */} + {}}/> { const type = deleteState.action - - let newData: any = [] - selectedRow.map((item: any) => newData.push(item.name)) let pk if (type == 'multiple') { + let newData: any = selectedRow.map((item: any) => item.name) pk = await saveRefenerceData({ name: newData.join(','), id: selectedRowKeys.join(',') }) // window.open(`/refenerce/conf/?name=${newData.join(',')}&id=${selectedRowKeys.join(',')}`) } else { diff --git a/src/pages/SystemConf/TestSuite/BusinessTest/FuncOrPerfConfList/components/MetricEditDrawer/index.tsx b/src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/FuncOrPerfConfList/components/MetricEditDrawer/index.tsx similarity index 100% rename from src/pages/SystemConf/TestSuite/BusinessTest/FuncOrPerfConfList/components/MetricEditDrawer/index.tsx rename to src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/FuncOrPerfConfList/components/MetricEditDrawer/index.tsx diff --git a/src/pages/SystemConf/TestSuite/BusinessTest/FuncOrPerfConfList/components/MetricTable/DeleteMetricPopover.less b/src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/FuncOrPerfConfList/components/MetricTable/DeleteMetricPopover.less similarity index 100% rename from src/pages/SystemConf/TestSuite/BusinessTest/FuncOrPerfConfList/components/MetricTable/DeleteMetricPopover.less rename to src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/FuncOrPerfConfList/components/MetricTable/DeleteMetricPopover.less diff --git a/src/pages/SystemConf/TestSuite/BusinessTest/FuncOrPerfConfList/components/MetricTable/DeleteMetricPopover.tsx b/src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/FuncOrPerfConfList/components/MetricTable/DeleteMetricPopover.tsx similarity index 100% rename from src/pages/SystemConf/TestSuite/BusinessTest/FuncOrPerfConfList/components/MetricTable/DeleteMetricPopover.tsx rename to src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/FuncOrPerfConfList/components/MetricTable/DeleteMetricPopover.tsx diff --git a/src/pages/SystemConf/TestSuite/BusinessTest/FuncOrPerfConfList/components/MetricTable/index.tsx b/src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/FuncOrPerfConfList/components/MetricTable/index.tsx similarity index 100% rename from src/pages/SystemConf/TestSuite/BusinessTest/FuncOrPerfConfList/components/MetricTable/index.tsx rename to src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/FuncOrPerfConfList/components/MetricTable/index.tsx diff --git a/src/pages/SystemConf/TestSuite/BusinessTest/FuncOrPerfConfList/index.less b/src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/FuncOrPerfConfList/index.less similarity index 100% rename from src/pages/SystemConf/TestSuite/BusinessTest/FuncOrPerfConfList/index.less rename to src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/FuncOrPerfConfList/index.less diff --git a/src/pages/SystemConf/TestSuite/BusinessTest/FuncOrPerfConfList/index.tsx b/src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/FuncOrPerfConfList/index.tsx similarity index 98% rename from src/pages/SystemConf/TestSuite/BusinessTest/FuncOrPerfConfList/index.tsx rename to src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/FuncOrPerfConfList/index.tsx index 8f584c6a00901e3dbc5b81d61ab4f2205c750838..df40ff88d08f474c9df93630f8dd7603648a014e 100644 --- a/src/pages/SystemConf/TestSuite/BusinessTest/FuncOrPerfConfList/index.tsx +++ b/src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/FuncOrPerfConfList/index.tsx @@ -172,11 +172,9 @@ export default forwardRef(({ id, type: test_type, domainList }: any, ref: any) = } const handleDetail = async () => { - let newData: any = [] - selectedRow.foreach((item: any) => newData.push(item.name)) - let pk if (!deleteObj.id) { + let newData: any = selectedRow.map((item: any) => item.name) pk = await saveRefenerceData({ name: newData.join(','), id: selectedRowKeys.join(',') }) } else { const { name, id } = deleteObj @@ -360,13 +358,13 @@ export default forwardRef(({ id, type: test_type, domainList }: any, ref: any) = {/** 编辑说明 */} - {/** 200表示删除有引用;*/} + {/** 200表示有引用,不能直接删除;*/} } footer={[ - , + // , diff --git a/src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/SuiteList/AddSuiteDrawer/index.tsx b/src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/SuiteList/AddSuiteDrawer/index.tsx index 1f9cd5c1997635485d65968ba36b0a9f9001a599..845846fb7fdba1206cd0e773fa30e29bce452678 100644 --- a/src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/SuiteList/AddSuiteDrawer/index.tsx +++ b/src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/SuiteList/AddSuiteDrawer/index.tsx @@ -88,17 +88,17 @@ export default forwardRef((props: any, ref: any) => { setPadding(true) form.validateFields().then(async (values) => { const { business_id, id } = editData; + const domain_list_str = values.domain_list_str.join() if (id) { - const { code, msg } = await editSuite(id, { ...values, domain_list_str: values.domain_list_str.join() }) + const { code, msg } = await editSuite(id, { ...values, domain_list_str }) defaultOption(code, msg, 'edit') } else { - const { code, msg } = await addSuite2({ business_id, ...values, domain_list_str: values.domain_list_str.join() }) + const { code, msg } = await addSuite2({ business_id, ...values, domain_list_str }) defaultOption(code, msg, 'add') } setPadding(false) }).catch((err) => { setPadding(false) - // console.log(err) // 单独校验业务名称 err?.errorFields?.forEach((item: any)=> { if (item.name[0] === 'name') { diff --git a/src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/SuiteList/index.tsx b/src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/SuiteList/index.tsx index 1064fc3b4540ff2e58ce92a333422d59bbc8d8bd..910f3e6ffe1bdd81bea6130bb2bdfe8d50559518 100644 --- a/src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/SuiteList/index.tsx +++ b/src/pages/SystemConf/TestSuite/BusinessTest/BusinessList/components/SuiteList/index.tsx @@ -7,8 +7,9 @@ import CommonTable from '@/components/Public/CommonTable'; import { test_type_enum, runList, saveRefenerceData } from '@/utils/utils' import ConfList from '../ConfList'; import AddSuiteDrawer from './AddSuiteDrawer'; -import FuncOrPerfConfList from '../../../FuncOrPerfConfList'; +import FuncOrPerfConfList from '../FuncOrPerfConfList'; import { querySuiteList, getDomain, syncSuite, delSuite, queryDelSuiteAll, deleteBusinessSuiteAll } from '../../../../service'; +import SynchronizeModal from '../../../../BasicTest/components/SynchronizeModal'; import { queryConfirm } from '@/pages/WorkSpace/JobTypeManage/services'; import styles from './index.less'; import { ColumnEllipsisText } from '@/components/ColumnComponents'; @@ -35,6 +36,7 @@ export default forwardRef(({ business_id, rowSelectionCallback = () => { }, rest const [deleteState, setDeleteState] = useState({ visible: false, result: '', action: '' }) // action:单个/批量删除 const [deleteRow, setDeleteRow] = useState({}) const [deleteLoading, setDeleteLoading] = useState(false) + const synchronizeRef: any = useRef(null) // 1.请求列表数据 const getTableData = async (query: any) => { @@ -90,6 +92,7 @@ export default forwardRef(({ business_id, rowSelectionCallback = () => { }, rest setLoading(false) } } + // 4.单个删除 const getDelSuite = async () => { setDeleteLoading(true) @@ -154,22 +157,44 @@ export default forwardRef(({ business_id, rowSelectionCallback = () => { }, rest if (type === 'multiple') { const pk = await saveRefenerceData({ name: newData.join(','), id: selectedRowKeys.join(',') }) - // window.open(`/refenerce/conf/?name=${newData.join(',')}&id=${selectedRowKeys.join(',')}`) window.open(`/refenerce/conf/?pk=${pk}`) } else if (type === 'single') { const { name, id } = deleteRow const pk = await saveRefenerceData({ name, id }) - // window.open(`/refenerce/suite/?name=${deleteRow.name}&id=${deleteRow.id}`) window.open(`/refenerce/suite/?pk=${pk}`) } } + // 7.同步弹窗: 201有引用 + const onSynchronize = async (row: any) => { + const hide = message.loading({ content: formatMessage({ id: 'operation.synchronizing' }), duration: 0 }) + const res = await syncSuite(row.id) || {} + hide() + // 判断 200无引用 + if (res.code === 200) { + message.success(formatMessage({ id: 'request.synchronize.success' })) + getTableData({ page_num: data.page_num, page_size: data.page_size }) + // case2.刷新已展开的conf列表 + if (expandKeys.includes(row.id)) { + caseTable.current?.refresh({ refreshId: row.id }) + } else { + const ids = expandKeys.concat([row.id]) + setExpandKeys(ids) + } + } else if (res.code === 201) { + // 判断 201有引用 + const { id, name } = row + synchronizeRef.current?.show({ id, name, ...res.data }) + } else { + synchronizeRef.current?.show({ code: res.code, msg: res.msg }) + } + } // 打开对话框 - const onOk = (data: any, record: any, action: any) => { + const onOk = (res: any, record: any, action: any) => { // 删除查询:200表示有引用,201表示可以直接删除 - if (data.code === 200) { + if (res.code === 200) { setDeleteState({ visible: true, result: 200, action }) - } else if (data.code === 201) { + } else if (res.code === 201) { setDeleteState({ visible: true, result: 201, action }) } setDeleteRow(record) @@ -243,9 +268,9 @@ export default forwardRef(({ business_id, rowSelectionCallback = () => { }, rest // 单个删除前查询 const queryDeleteSingle = async ({ record = {} }: any) => { try { - const data = await queryConfirm({ flag: 'pass', suite_id: record.id }) || {} - if (data.code) { - onOk(data, record, 'single') + const res = await queryConfirm({ flag: 'pass', suite_id: record.id }) || {} + if (res.code) { + onOk(res, record, 'single') } } catch (e) { console.log(e) @@ -254,9 +279,9 @@ export default forwardRef(({ business_id, rowSelectionCallback = () => { }, rest // 批量删除前查询 const queryDeleteAll = async () => { try { - const data = await queryDelSuiteAll({ flag: 'pass', suite_id_list: selectedRowKeys.join() }) || {} - if (data.code) { - onOk(data, {}, 'multiple') + const res = await queryDelSuiteAll({ flag: 'pass', suite_id_list: selectedRowKeys.join() }) || {} + if (res.code) { + onOk(res, {}, 'multiple') } } catch (e) { console.log(e) @@ -356,10 +381,10 @@ export default forwardRef(({ business_id, rowSelectionCallback = () => { }, rest render: (text: any, record: any) => { return ( - {(record.test_type === 'business') ? ( + {record.test_type === 'business' ? (    ) : ( - getSyncSuite(record.id)}> + onSynchronize(record)}> )} handelAddOrEdit({ type: 'edit', record })}> queryDeleteSingle({ record })}> @@ -427,10 +452,13 @@ export default forwardRef(({ business_id, rowSelectionCallback = () => { }, rest expanded ? ( onExpand(record, e)} />) : ( onExpand(record, e)} />) }} - // scrollType={1250} scroll={{ x: 1250 }} paginationBottom={true} /> + + {/* 同步弹窗 */} + {}}/> + } centered={true} okText={} @@ -473,7 +501,7 @@ export default forwardRef(({ business_id, rowSelectionCallback = () => { }, rest )} - + ) diff --git a/src/pages/SystemConf/TestSuite/index.tsx b/src/pages/SystemConf/TestSuite/index.tsx index e275adf0ce940391c9cfefd24a7679209c22f19a..c6ce2309881a0d8ebcba2324887d5af1e53bfa5b 100644 --- a/src/pages/SystemConf/TestSuite/index.tsx +++ b/src/pages/SystemConf/TestSuite/index.tsx @@ -1,7 +1,7 @@ -import React, { useMemo, useRef } from 'react' +import React, { useState, useMemo, useRef } from 'react' import { TabCard } from '@/components/UpgradeUI' -import { Tabs, Button } from 'antd' +import { Tabs, Button, Spin } from 'antd' import { history, useLocation, useIntl, FormattedMessage } from 'umi' import BasicTest from './BasicTest' @@ -14,9 +14,10 @@ import { runList } from '@/utils/utils'; const TestSuite: React.FC = () => { const { formatMessage } = useIntl() const { query }: any = useLocation() - + const [synchronizeLoading, setSynchronizeLoading] = useState(false) + const testType = useMemo(() => { - return !query.test_type ? 'functional' : query.test_type + return query.test_type || 'functional' }, [query]) const domainList = useDomain() @@ -47,40 +48,43 @@ const TestSuite: React.FC = () => { ] }} > - - } key="functional" /> - } key="performance" /> - {!BUILD_APP_ENV ? } key="business" /> : null} - } key="domainconf" /> - - } - extra={ - - } - > - { - (testType !== 'business' && testType !== 'domainconf') && - - } - { - testType === 'business' && - - } - { - testType === 'domainconf' && - - } - + + + } key="functional" /> + } key="performance" /> + {!BUILD_APP_ENV ? } key="business" /> : null} + } key="domainconf" /> + + } + extra={ + + } + > + { + ['functional', 'performance'].includes(testType) && + + } + { + testType === 'business' && + + } + { + testType === 'domainconf' && + + } + + ) } diff --git a/src/pages/SystemConf/UserManagement/components/RoleSelect/index.tsx b/src/pages/SystemConf/UserManagement/components/RoleSelect/index.tsx index 16baefef4dca779aaa32e2bce661042d96923fb5..171c64d1f88fa727ffbdc55c454c717da301a7ee 100644 --- a/src/pages/SystemConf/UserManagement/components/RoleSelect/index.tsx +++ b/src/pages/SystemConf/UserManagement/components/RoleSelect/index.tsx @@ -26,11 +26,9 @@ const RoleSelect: React.FC<{ row: any, select: any[], handleChange: (val: number } useEffect(() => { - setSelectValue(row.role_list.map((item: any) => (item.id))[0]) + setSelectValue(row?.role_list?.map((item: any) => (item.id))[0]) }, [row.role_list]) - // console.log('selectValue:', selectValue) - return (
diff --git a/src/pages/WorkSpace/DeviceManage/CloudManage/AddMachinePubilc/index.tsx b/src/pages/WorkSpace/DeviceManage/CloudManage/AddMachinePubilc/index.tsx index d9d1a663d71d89b5db1af44522adb74c99d97a0f..168ba723b06ec446e265c208aab89377ebadb55e 100644 --- a/src/pages/WorkSpace/DeviceManage/CloudManage/AddMachinePubilc/index.tsx +++ b/src/pages/WorkSpace/DeviceManage/CloudManage/AddMachinePubilc/index.tsx @@ -1117,7 +1117,7 @@ const NewMachine: React.FC = (props) => { - {!is_instance && BUILD_APP_ENV === 'openanolis' && + {!is_instance && BUILD_APP_ENV !== 'opensource' && = (props) => { rules={[{ required: false, message: formatMessage({ id: 'please.select' }) }]} > - + {BUILD_APP_ENV === 'openanolis' && + + } diff --git a/src/pages/WorkSpace/DeviceManage/CloudManage/Aligroup/index.tsx b/src/pages/WorkSpace/DeviceManage/CloudManage/Aligroup/index.tsx index 65f3beaf9ade0052fea98cfa4f47e09ff4a6f013..bdd2a30ff50fcbde01d6db27284230b47370c4d8 100644 --- a/src/pages/WorkSpace/DeviceManage/CloudManage/Aligroup/index.tsx +++ b/src/pages/WorkSpace/DeviceManage/CloudManage/Aligroup/index.tsx @@ -14,10 +14,11 @@ import SelectTags from '@/components/Public/SelectTags'; import Highlighter from 'react-highlight-words'; import AddCluster from './AddGroup' import { FilterFilled } from '@ant-design/icons'; -import { useParams, useIntl, FormattedMessage, useLocation, history } from 'umi'; +import { useParams, useIntl, FormattedMessage, useLocation, history, getLocale } from 'umi'; import { useClientSize } from '@/utils/hooks'; import { AccessTootip, handlePageNum, requestCodeMessage, saveRefenerceData, useStateRef } from '@/utils/utils'; import { Access, useAccess } from 'umi' +import SelectRadio from '@/components/Public/SelectRadio'; import Log from '@/components/Public/Log'; import OverflowList from '@/components/TagOverflow/index'; import CommonPagination from '@/components/CommonPagination'; @@ -35,6 +36,7 @@ interface AligroupParams { page_num?: number, page_size?: number, name?: string, + is_temporary?: string, owner?: any, tags?: any, description?: string, @@ -45,6 +47,7 @@ const Aligroup: React.ForwardRefRenderFunction = (props) => { const { tab } = props const { query } = useLocation() as any const { formatMessage } = useIntl() + const enLocale = getLocale() === 'en-US' const { ws_id }: any = useParams() const [form] = Form.useForm(); const access = useAccess(); @@ -85,8 +88,11 @@ const Aligroup: React.ForwardRefRenderFunction = (props) => { const getList = async ($params: any = {}) => { setLoading(true) const data: any = await querysCluster({ ...$params }) - history.replace(`/ws/${ws_id}/device/cloud?${stringify({ ...$params, is_instance: $params.is_instance ? 1 : 0 })}`) - data && setSource(data) + if (data.code === 200) { + history.replace(`/ws/${ws_id}/device/cloud?${stringify({ ...$params, is_instance: $params.is_instance ? 1 : 0 })}`) + console.log('data:', data) + data && setSource(data) + } setLoading(false) }; const totalCurrent = useStateRef(source) @@ -175,6 +181,18 @@ const Aligroup: React.ForwardRefRenderFunction = (props) => { filterIcon: () => , }) + const radioFilterCommonFields = (dataIndex: string, list: any[]) => ({ + filterIcon: () => , + filterDropdown: ({ confirm }: any) => ( + setParams({ ...params, [dataIndex]: val, page_num: 1 })} + /> + ), + }) + const columns: any = [ { title: , @@ -192,6 +210,22 @@ const Aligroup: React.ForwardRefRenderFunction = (props) => { ) }, + { + title: , + ...radioFilterCommonFields("is_temporary", [ + { id: 0, name: formatMessage({ id: 'cluster' }) }, + { id: 1, name: formatMessage({ id: 'device.temporary.cluster' }) }, + ]), + dataIndex: 'is_temporary', + width: enLocale ? 170 : 150, + ellipsis: { + showTitle: false + }, + render: (_: any, row: any) => { + const text = _ ? formatMessage({ id: 'device.temporary.cluster' }): formatMessage({ id: 'cluster' }) + return {row.hasOwnProperty('is_temporary') ? text: '-'} + } + }, { title: 'Owner', dataIndex: 'owner_name', diff --git a/src/pages/WorkSpace/DeviceManage/GroupManage/Cluster/index.tsx b/src/pages/WorkSpace/DeviceManage/GroupManage/Cluster/index.tsx index fcd16df3d9688d5a1eeed540a2021c065e6b2bf5..fd90623a642ed5d7272a3ad6c216bea7a3e14d25 100644 --- a/src/pages/WorkSpace/DeviceManage/GroupManage/Cluster/index.tsx +++ b/src/pages/WorkSpace/DeviceManage/GroupManage/Cluster/index.tsx @@ -1,6 +1,6 @@ import { useState, useCallback, useRef, forwardRef, useImperativeHandle } from 'react' import styles from './index.less' -import { useIntl, FormattedMessage, useParams } from 'umi' +import { useIntl, FormattedMessage, useParams, getLocale } from 'umi' import { Layout, Button, Space, Tag, message, Typography, Spin, Modal, Table } from 'antd' import { deleteServerGroup, queryServerDel } from '../services' import { CaretRightFilled, FilterFilled, ExclamationCircleOutlined } from '@ant-design/icons' @@ -15,6 +15,7 @@ import CommonPagination from '@/components/CommonPagination' import { usePageInit } from './hooks' import { requestCodeMessage, AccessTootip, saveRefenerceData } from '@/utils/utils'; import { Access, useAccess } from 'umi'; +import SelectRadio from '@/components/Public/SelectRadio'; import OverflowList from '@/components/TagOverflow/index' import { ColumnEllipsisText } from '@/components/ColumnComponents' import { v4 as uuid } from 'uuid' @@ -26,6 +27,7 @@ import DelConfirmModal from "@/pages/WorkSpace/DeviceManage/components/DelConfir */ const Cluster = (props: any, ref: any) => { const { formatMessage } = useIntl() + const enLocale = getLocale() === 'en-US' const { ws_id } = useParams() as any const access = useAccess(); const { loading, dataSource, params, setParams, setRefresh } = usePageInit() @@ -101,6 +103,18 @@ const Cluster = (props: any, ref: any) => { }, [] ) + const radioFilterCommonFields = (dataIndex: string, list: any[]) => ({ + filterIcon: () => , + filterDropdown: ({ confirm }: any) => ( + setParams({ ...params, [dataIndex]: val, page_num: 1 })} + /> + ), + }) + const columns: any = [ { title: , @@ -111,6 +125,22 @@ const Cluster = (props: any, ref: any) => { setParams({ ...params, page_num: 1, name })} /> ) }, + { + title: , + ...radioFilterCommonFields("is_temporary", [ + { id: 0, name: formatMessage({ id: 'cluster' }) }, + { id: 1, name: formatMessage({ id: 'device.temporary.cluster' }) }, + ]), + dataIndex: 'is_temporary', + width: enLocale ? 170 : 150, + ellipsis: { + showTitle: false + }, + render: (_: any, row: any) => { + const text = _ ? formatMessage({ id: 'device.temporary.cluster' }): formatMessage({ id: 'cluster' }) + return {row.hasOwnProperty('is_temporary') ? text: '-'} + } + }, { title: 'Owner', width: 150, diff --git a/src/pages/WorkSpace/DeviceManage/locales/en-US.ts b/src/pages/WorkSpace/DeviceManage/locales/en-US.ts index c2ddbdf82ff2d6bb42da90ba785a083a60734c71..4b0ac6500cf95596003428b0eafed59eb3887afb 100644 --- a/src/pages/WorkSpace/DeviceManage/locales/en-US.ts +++ b/src/pages/WorkSpace/DeviceManage/locales/en-US.ts @@ -109,6 +109,9 @@ export default { 'device.cluster.name.s': 'Cluster Name', 'device.cluster.name.s.message': 'Cluster name cannot be empty.', 'device.cluster.name.s.existed': 'Cluster name already exists', + 'device.cluster/temporary.cluster': 'Cluster/Temporary Cluster', + // '集群': '集群', + 'device.temporary.cluster': 'Temporary Cluster', 'please.select.owner': 'Please select Owner', 'device.cluster.delete.tips': 'The cluster has been configured with an existing template. After deleting the server, the corresponding test server configuration will be automatically changed to random. Please delete it carefully.', 'device.is_single': 'Is it from the stand-alone pool?', @@ -155,8 +158,8 @@ export default { 'device.extended.fields': 'Extended Fields', 'device.aliyun.params': 'Alibaba Cloud openAPI parameters', 'device.toneagent.working.mode': 'Toneagent working mode', - 'device.active.mode': 'Active mode', - 'device.passive.mode': 'Passive mode', + 'device.active.mode': 'Active', + 'device.passive.mode': 'Passive', 'device.tips': 'Tips', 'device.delete.config': 'Are you sure you want to delete the configuration ({data})?', 'device.delete.instance': 'Are you sure you want to delete the instance({data})?', diff --git a/src/pages/WorkSpace/DeviceManage/locales/zh-CN.ts b/src/pages/WorkSpace/DeviceManage/locales/zh-CN.ts index 67f94df173934962ae7fc21476232b90cf1af6da..e449504198deb00fb0091ff4c6730401c5d8ce8c 100644 --- a/src/pages/WorkSpace/DeviceManage/locales/zh-CN.ts +++ b/src/pages/WorkSpace/DeviceManage/locales/zh-CN.ts @@ -109,6 +109,9 @@ export default { 'device.cluster.name.s': '集群名称', 'device.cluster.name.s.message': '集群名称不能为空', 'device.cluster.name.s.existed': '集群名称已存在', + 'device.cluster/temporary.cluster': '集群/临时集群', + // '集群': '集群', + 'device.temporary.cluster': '临时集群', 'please.select.owner': '请选择Owner', 'device.cluster.delete.tips': '已有模板配置了该集群,删除机器后对应的测试机配置会自动改为随机,请谨慎删除!!', 'device.is_single': '是否是单机池', diff --git a/src/pages/WorkSpace/TestAnalysis/AnalysisCompare/AllJobTable.tsx b/src/pages/WorkSpace/TestAnalysis/AnalysisCompare/AllJobTable.tsx index 3cb20fd1b7f947ad3437efbc5a742f025402465f..709038d71510df9242bdf6db45dea21958fee2ff 100644 --- a/src/pages/WorkSpace/TestAnalysis/AnalysisCompare/AllJobTable.tsx +++ b/src/pages/WorkSpace/TestAnalysis/AnalysisCompare/AllJobTable.tsx @@ -20,9 +20,12 @@ import { Scrollbars } from 'react-custom-scrollbars'; import SelectRadio from '@/components/Public/SelectRadio'; import SelectUser from '@/components/Public/SelectUser'; import CommonPagination from '@/components/CommonPagination'; +import { ColumnEllipsisText } from '@/components/ColumnComponents'; +import WsListSelect from '@/pages/WorkSpace/TestReport/components/WsListSelect' + import { requestCodeMessage } from '@/utils/utils' import { ResizeHooksTable } from '@/utils/table.hooks'; -import { ColumnEllipsisText } from '@/components/ColumnComponents'; + const { RangePicker } = DatePicker const { Option } = Select @@ -68,8 +71,9 @@ const AllJobTable: React.ForwardRefRenderFunction = (props, re { id: 1, name: formatMessage({ id: 'header.test_type.functional' }) }, { id: 0, name: formatMessage({ id: 'header.test_type.performance' }) }, ] - const [pruductId, setPruductId] = useState() - const [pruductVersion, setPruductVersion] = useState() + const [selectedWsId, setSelectedWsId] = useState() + const [productId, setProductId] = useState() + const [productVersion, setProductVersion] = useState() const [dataSource, setDataSource] = useState(defaultResult) React.useImperativeHandle(ref, () => ({ @@ -86,28 +90,28 @@ const AllJobTable: React.ForwardRefRenderFunction = (props, re confirm?.() } - const getProductList = async (id: any) => { + const getProductList = async (q: any) => { setLoading(true) - const result = await queryProductList({ ws_id, product_id: id }) + const result = await queryProductList(q) if (result.code === 200) { let data = result.data.filter((val: any) => val?.trim()) data = data.map((item: any, index: number) => ({ label: index, value: item })) setAllVersion(data) - if (!!data.length && pruductId) setPruductVersion(data[0].value) - else setPruductVersion(undefined) + if (data.length && productId) setProductVersion(data[0].value) + else setProductVersion(undefined) } else { requestCodeMessage(result.code, result.msg) } setLoading(false) } - const getProductData = async () => { + const getProductData = async (q: any) => { setLoading(true) - const result = await queryProduct({ ws_id }) + const result = await queryProduct(q) if (result.code === 200) { const data = _.isArray(result.data) ? result.data : [] setAllProduct(data) - if (!!data.length) setPruductId(undefined) + setProductId(data[0].id) } else { requestCodeMessage(result.code, result.msg) } @@ -116,10 +120,10 @@ const AllJobTable: React.ForwardRefRenderFunction = (props, re const getJobList = async () => { setLoading(true) - const data = await queryJobList(params) + const data = await queryJobList({ ...params, ws_id: selectedWsId, }) + setLoading(false) if (data.code === 200) { setDataSource(data) - setLoading(false) } else { setDataSource(defaultResult) requestCodeMessage(data.code, data.msg) @@ -217,7 +221,9 @@ const AllJobTable: React.ForwardRefRenderFunction = (props, re shwoTitle: false, }, dataIndex: 'creator_name', - filterDropdown: ({ confirm }: any) => + setParams({ ...params, creators: val ? JSON.stringify([val]) : null })} page_size={9999} />, onFilterDropdownVisibleChange: (visible: any) => { @@ -257,43 +263,52 @@ const AllJobTable: React.ForwardRefRenderFunction = (props, re ] useEffect(() => { - getProductData() - getProductList(undefined) - }, []) + if (ws_id) { + setSelectedWsId(ws_id) + getProductData({ ws_id }) + } + }, [ws_id]) useEffect(() => { - if (pruductId) getProductList(pruductId) - }, [pruductId]) + if (productId) getProductList({ ws_id: selectedWsId, product_id: productId }) + }, [productId]) useEffect(() => { - getJobList() - }, [params]) + if (productId) { + setParams({ ...params, ws_id: selectedWsId, product_id: productId, product_version: productVersion || undefined }) + } + }, [productVersion]) useEffect(() => { - if (pruductId && !pruductVersion) { - setParams({ ...params, product_id: pruductId, product_version: undefined }) - } - if (pruductId && pruductVersion) { - setParams({ ...params, product_version: pruductVersion, product_id: pruductId }) - } - }, [pruductId, pruductVersion]) + getJobList() + }, [params]) const onVersionChange = (value: any) => { - setPruductVersion(value) + setProductVersion(value) + } + + const onWsChange = (value: any) => { + // 重置其他控件选项 + setProductId(undefined) + setProductVersion(undefined) + setDataSource(defaultResult) + // + setSelectedWsId(value) + getProductData({ ws_id: value }) } const onProductChange = (value: any) => { - setPruductId(value) + setProductId(value) } const handleClearVersion = () => { - setPruductVersion(undefined) + setProductVersion(undefined) setParams({ ...params, product_version: undefined }) } const handleClearProduct = () => { - setPruductId(undefined) - setPruductVersion(undefined) + setProductId(undefined) + setProductVersion(undefined) setParams(page_default_params) } @@ -350,7 +365,7 @@ const AllJobTable: React.ForwardRefRenderFunction = (props, re } }, }; - const handleSelectCancle = () => { + const handleSelectCancel = () => { setSelectedRowKeys([]); setSelectRowData([]); } @@ -386,14 +401,23 @@ const AllJobTable: React.ForwardRefRenderFunction = (props, re
- + + + + + - + { - getProductVersionsList(value) - .then((list: any) => { - const newVersion = list && list.length > 0 ? list[0] : undefined - setListParams((p: any) => ({ ...p, page_num: 1, product_id: value, product_version: newVersion })) - setProductVersions(list) - setSelectedRowDatas([]) - }) - }} - options={ - products?.map((item: any) => ({ - value: item.id, - label: item.name - })) - } - /> - - + +
+ + +
- - - - - { + getProductVersionsList(value) + .then((list: any) => { + const newVersion = list && list.length > 0 ? list[0] : undefined + setListParams((p: any) => ({ ...p, page_num: 1, product_id: value, product_version: newVersion })) + setProductVersions(list) + setSelectedRowDatas([]) + }) + }} + options={ + products?.map((item: any) => ({ + value: item.id, + label: item.name + })) + } + /> +
+ + +
+ + +
{ const { conf_id, conf_name, metric_list } = conf let baseJobList = isOldReport ? [conf?.obj_id || conf.conf_source?.obj_id] : [] - let compareJobList = (conf.conf_compare_data || conf.compare_conf_list).map((i: any) => ({ job_id: i?.obj_id || '', is_baseline: i?.is_baseline })) + let compareJobList = (conf.conf_compare_data || conf.compare_conf_list).map((i: any) => ({ job_id: i?.obj_id || '', is_baseline: i?.is_baseline, ws_id: i?.ws_id })) conf_list.push({ conf_id, conf_name, diff --git a/src/pages/WorkSpace/TestReport/NewReport/components/TestDataChild/ChartTypeChild.tsx b/src/pages/WorkSpace/TestReport/NewReport/components/TestDataChild/ChartTypeChild.tsx index 98747a69d4c42263576c43e15ca495e2f97e5269..65cf84c17f746620c9bff6811ef0d3fd5955d3e9 100644 --- a/src/pages/WorkSpace/TestReport/NewReport/components/TestDataChild/ChartTypeChild.tsx +++ b/src/pages/WorkSpace/TestReport/NewReport/components/TestDataChild/ChartTypeChild.tsx @@ -1,10 +1,8 @@ -import { useState, useEffect } from 'react'; import { Typography, Space, Select, } from 'antd'; import { FormattedMessage } from 'umi'; const ChartTypeChild = (props: any) => { const { btn, isReport, obj, suiteId, setPerData, chartType, setChartType } = props; - // const [chartType, setChartType] = useState('1') const onChange = (val: string) => { setChartType(val) if (isReport) { diff --git a/src/pages/WorkSpace/TestReport/NewReport/components/TestDataChild/FuncReview.tsx b/src/pages/WorkSpace/TestReport/NewReport/components/TestDataChild/FuncReview.tsx index 4c472a8998f5556867caa5bbd82e3d2c0a16d4a0..dd9f6b3b7a7c910a2b275e1dcb2ab4c59e830642 100644 --- a/src/pages/WorkSpace/TestReport/NewReport/components/TestDataChild/FuncReview.tsx +++ b/src/pages/WorkSpace/TestReport/NewReport/components/TestDataChild/FuncReview.tsx @@ -377,7 +377,7 @@ const FuncDataIndex: React.FC = (props) => { else setExpandKeys(expandKeys.concat(id)) } - + const functionTable = Array.isArray(funcData.list) && !!funcData.list.length ? funcData?.list?.map((suite: any, idx: number) => { return ( @@ -506,6 +506,8 @@ const FuncDataIndex: React.FC = (props) => { { dataList?.map((item: any, idx: number) => { + // selected_ws_id 这段逻辑,用于兼容老数据,后续删除 + const selected_ws_id = suite.group_jobs?.filter((jobObj: any)=> jobObj?.job_list?.includes(item.obj_id))[0].ws_id || wsId return ( @@ -514,7 +516,7 @@ const FuncDataIndex: React.FC = (props) => { {toShowNum(item.fail_case)} { !share_id && !getCompareType(item) && - + } diff --git a/src/pages/WorkSpace/TestReport/NewReport/components/TestDataChild/PrefReview.tsx b/src/pages/WorkSpace/TestReport/NewReport/components/TestDataChild/PrefReview.tsx index 3d83a4e8038b1e90731480c8a885b4dd0de6f70f..8624f4fbfde686c8a8faa36f4773c0e4c1906f39 100644 --- a/src/pages/WorkSpace/TestReport/NewReport/components/TestDataChild/PrefReview.tsx +++ b/src/pages/WorkSpace/TestReport/NewReport/components/TestDataChild/PrefReview.tsx @@ -211,7 +211,7 @@ const Performance = (props: any) => { })) } - const renderShare = (conf: any) => { + const renderShare = (conf: any, group_jobs: any) => { let objList: any = [] let objConf = conf?.conf_source || conf allGroupData?.map((c: any, i: number) => { @@ -224,11 +224,13 @@ const Performance = (props: any) => { return ( arr.map((item: any, idx: number) => { if (!item) return <> + // selected_ws_id 这段逻辑,用于兼容老数据,后续删除 + const selected_ws_id = group_jobs?.filter((jobObj: any)=> jobObj?.job_list?.includes(item.obj_id))[0].ws_id || wsId return ( { !share_id && !getCompareType(item) ? - : + :
} @@ -349,7 +351,7 @@ const Performance = (props: any) => { - {renderShare(conf)} + {renderShare(conf, suite.group_jobs)} { conf.metric_list.map((metric: any, idx: number) => ( diff --git a/src/pages/WorkSpace/TestReport/NewReport/hooks.ts b/src/pages/WorkSpace/TestReport/NewReport/hooks.ts index 05deedef5ec0295f0766c26a4e416a823d9f56b7..9370048702651bbce61d963a7e5e562cca7c4fe0 100644 --- a/src/pages/WorkSpace/TestReport/NewReport/hooks.ts +++ b/src/pages/WorkSpace/TestReport/NewReport/hooks.ts @@ -81,24 +81,30 @@ export const CreatePageData = (props: any) => { let resLen: any = [] resLen = perfArr.concat(funcArr) setSuiteLen(resLen.length) - resLen.map((item: any, i: number) => queryCompareResultFn(item) - .then(res => { - if (res.code === 200) { - setLoading(false) - if (res.data.test_type === 'functional') { - compareResult.func_data_result = compareResult.func_data_result.concat(res.data) + try { + resLen.map((item: any, i: number) => queryCompareResultFn(item) + .then(res => { + if (res.code === 200) { + setLoading(false) + if (res.data.test_type === 'functional') { + compareResult.func_data_result = compareResult.func_data_result.concat(res.data) + } + if (res.data.test_type === 'performance') { + compareResult.perf_data_result = compareResult.perf_data_result.concat(res.data) + } } - if (res.data.test_type === 'performance') { - compareResult.perf_data_result = compareResult.perf_data_result.concat(res.data) + setCompareResult({ ...compareResult }) + if (res.code !== 200) { + message.error(res.msg) + return } - } - setCompareResult({ ...compareResult }) - if (res.code !== 200) { - message.error(res.msg) - return - } - }) - ) + }) + ) + } catch (error) { + setLoading(false) + } finally { + setLoading(false) + } } useEffect(() => { @@ -350,6 +356,7 @@ export const CreatePageData = (props: any) => { list.push({ ...item, test_suite_description: suite[b].test_tool, + suite_name: suite[b].suite_show_name, test_env: '', test_description: '', test_conclusion: '', @@ -389,6 +396,7 @@ export const CreatePageData = (props: any) => { list.push({ ...item, test_suite_description: suite[b].test_tool, + suite_name: suite[b].suite_show_name, rowKey: `${m}-${b}` }) } @@ -422,6 +430,7 @@ export const CreatePageData = (props: any) => { if (Number(item.suite_id) === Number(suite[b].test_suite_id)) { list.push({ ...item, + suite_name: suite[b].suite_show_name, rowKey: `${m}-${b}` }) } @@ -451,11 +460,11 @@ export const CreatePageData = (props: any) => { let list: any = [] let conf_list: any = [] for (let suite = res[m].list, b = 0; b < suite.length; b++) { //遍历项下面的suite - func_data_result?.map((item: any, idx: number) => { if (Number(item.suite_id) === Number(suite[b].test_suite_id)) { list.push({ ...item, + suite_name: suite[b].suite_show_name, rowKey: `${m}-${b}` }) } @@ -650,7 +659,6 @@ export const EditPageData = () => { } setDataSource(data) // window.document.title = data?.name || 'T-one' - // console.log(data) const { tmpl_id, creator, template_detail } = data setCreator(creator) let templateSource = template_detail diff --git a/src/pages/WorkSpace/TestReport/components/WsListSelect/index.less b/src/pages/WorkSpace/TestReport/components/WsListSelect/index.less new file mode 100644 index 0000000000000000000000000000000000000000..fbcd864577556f663f0e393820e3bdb7c5dbc000 --- /dev/null +++ b/src/pages/WorkSpace/TestReport/components/WsListSelect/index.less @@ -0,0 +1,90 @@ + +.job_drop_menu { + background: #FFFFFF; + box-shadow: 0 9px 28px 8px rgba(0,0,0,0.05), 0 6px 16px 0 rgba(0,0,0,0.08), 0 3px 6px -4px rgba(0,0,0,0.12); + border-radius: 2px; + .create_job_type_text{ + cursor: pointer; + margin-right: 25px; + } + .create_job_type_text:hover{ + color: #1890ff; + } + ul,li{ + list-style: none; + margin: 0; + padding: 0; + } + .test_type{ + display: flex; + padding-left: 20px; + margin-bottom: 16px; + li{ + margin-right: 16px; + cursor: pointer; + } + } +} + +.menu_scroll { + :global { + /* 设置滚动条的样式 */ + ::-webkit-scrollbar { + width:4px; + background-color: #FFFFFF; + } + + /* 滚动槽 */ + ::-webkit-scrollbar-track { + border-radius:2px; + } + + /* 滚动条滑块 */ + ::-webkit-scrollbar-thumb { + border-radius:2px; + background:rgba(0,0,0,.1); + } + } +} + +.header_dorop_menu { + width: 240px; + overflow: auto; + max-height: 430px; + padding: 5px 0; +} + +.active { + color: #1890FF; + background-color: #f5f5f5; +} + +.active_typography { color : #1890FF;} + +.dropdownClass { + :global { + .ant-dropdown-arrow { + visibility: hidden; + } + } +} + +.workspaceDropdownMenu { + width: 220px; + overflow: auto; + max-height: 430px; + padding: 20px 0; + + :global { + .ant-dropdown-menu-item { + height:40px; + display:flex; + padding: 0 8px; + color: rgba(0, 0, 0, 0.85); + } + } + + .current_ws { + background:rgba(0,0,0,.02); + } +} \ No newline at end of file diff --git a/src/pages/WorkSpace/TestReport/components/WsListSelect/index.tsx b/src/pages/WorkSpace/TestReport/components/WsListSelect/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..9f469043891c84bf007f190c312093e7e6dff185 --- /dev/null +++ b/src/pages/WorkSpace/TestReport/components/WsListSelect/index.tsx @@ -0,0 +1,112 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +import React, { useState, useEffect } from 'react'; +import { Space, Avatar, Typography, Select, Spin } from 'antd'; +import { queryWorkspaceHistory, queryHomeWorkspace } from '@/services/Workspace' +import { useModel } from 'umi' +import { redirectErrorPage } from '@/utils/utils' +import styled from 'styled-components' + +const ShowName = styled(Typography.Text)` + width: 138px; + font-size: 14px; +` +interface CoverProps { + size: number + theme_color: string +} + +const Cover = styled.span` + display: inline-block; + border-radius : 4px; + font-size : 14px; + font-weight : bold; + width : ${({ size }) => size}px; + height : ${({ size }) => size}px; + line-height : ${({ size }) => size}px; + text-align : center; + color : #fff; + background : ${({ theme_color }) => theme_color}; +` +const WorkspaceCover: React.FC = ({ logo, show_name, theme_color }) => logo ? + + : + {show_name?.slice(0, 1)} + + + +const WsListSelect: React.FC = ({ ws_id, onChange=()=> {}, onSelect=()=> {}, onClear=()=> {}, value, ...rest }) => { + const [isOver, setIsOver] = useState(false) + const [loading, setLoading] = useState(false) + const [wsList, setWsList] = useState({ data: [], page_num: 1 }) + + const queryWorkspaceList = async (q?: any) => { + setLoading(true) + try { + const res = await queryHomeWorkspace({ + scope: 'powerful', + page_num: wsList.page_num, page_size: 999, + ...q, + }) + + if (res.code === 200) { + // setIsOver(res.total_page === res.page_num) + setWsList({ + ...res, data: res.data || [] + }) + } else { + redirectErrorPage(500) + } + setLoading(false) + } catch (err) { + setLoading(false) + } + } + + // const handleScroll = ({ target }: any) => { + // const { clientHeight, scrollTop, scrollHeight } = target + // if (clientHeight + scrollTop === scrollHeight && !isOver && Object.prototype.toString.call(wsList?.next) === '[object String]') { + // queryWorkspaceList({ page_num: wsList.page_num + 1 }) + // } + // } + + // const handleSearch = async (word?: string) => { + // console.log('word:', word) + // // const param = word && word.replace(/\s*/g, "") + // // queryWorkspaceList({ name: param, page_num: 1, ws_id }) + // } + + useEffect(() => { + queryWorkspaceList() + }, []); + + return ( + + ); +}; + +export default WsListSelect; diff --git a/src/pages/WorkSpace/TestResult/CompareBar/index.tsx b/src/pages/WorkSpace/TestResult/CompareBar/index.tsx index 081c19b0bea9692f68fc2017d6e100a2ad1980f9..11a072c653393952293afe552c7066d3ba4fd66c 100644 --- a/src/pages/WorkSpace/TestResult/CompareBar/index.tsx +++ b/src/pages/WorkSpace/TestResult/CompareBar/index.tsx @@ -202,7 +202,7 @@ export default (props: any) => { const perf_keys = Object.keys(perf_suite) || [] const duplicate: any = [] const allGroupData: any = [] - allGroupData.push({ members: allSelectRowData }) + allGroupData.push({ ws_id, members: allSelectRowData }) const newSuiteData = { func_suite_dic: getSelectedDataFn( func_suite, diff --git a/src/pages/WorkSpace/TestResult/Details/TestRsultTable/CaseTable.tsx b/src/pages/WorkSpace/TestResult/Details/TestRsultTable/CaseTable.tsx index 79432be273a2a008d4fe5a8586001a3da14798ea..c77235667b59b229d35b444e153a86a8ae2d2f98 100644 --- a/src/pages/WorkSpace/TestResult/Details/TestRsultTable/CaseTable.tsx +++ b/src/pages/WorkSpace/TestResult/Details/TestRsultTable/CaseTable.tsx @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/dot-notation */ /* eslint-disable react-hooks/exhaustive-deps */ -import { Table, Space, Row } from 'antd' +import { Table, Space, Row, Button, message } from 'antd' import React, { useEffect } from 'react' -import { Access, useAccess, useParams, FormattedMessage, getLocale } from 'umi' +import { Access, useAccess, useParams, FormattedMessage, useIntl, useModel, getLocale, request } from 'umi' import ServerLink from '@/components/MachineWebLink/index'; import { queryTestResultSuiteConfList } from '../service' import { CaretRightFilled, CaretDownFilled } from '@ant-design/icons'; @@ -21,6 +21,7 @@ import treeSvg from '@/assets/svg/tree.svg' import { AccessTootip } from '@/utils/utils'; import { getStorageState } from '@/utils/table.hooks'; import { MetricSelectProvider } from '.' +import { encode } from 'js-base64' // const treeSvg = require('@/assets/svg/tree.svg') const background = `url(${treeSvg}) center center / 38.6px 32px ` @@ -30,6 +31,8 @@ const CaseTable: React.FC> = (props) => { suite_id, testType, suite_name, server_provider, provider_name, creator, expandedState, expandedCaseRowKeys, openAllRows = false, setIndexExpandFlag, parentTableName, columnsChange } = props + const { formatMessage } = useIntl() + const { initialState } = useModel('@@initialState') const locale = getLocale() === 'en-US'; const { setOSuite, oSuite } = React.useContext(MetricSelectProvider) @@ -41,6 +44,7 @@ const CaseTable: React.FC> = (props) => { const [loading, setLoading] = React.useState(true) const [source, setSource] = React.useState([]) const [currentState, setCurrentState] = React.useState(expandedState) + // const [confLogInfo, setConfLogInfo] = React.useState({}) const init = async () => { setLoading(true) @@ -76,6 +80,39 @@ const CaseTable: React.FC> = (props) => { joinBaselineDrawer.current.show({ ..._, suite_id }) } + const handlePathClick = async (path: string, state: string) => { + let params: any = { + path: path, + job_id, share_id + } + + if (state === 'download') { + params.download = '1' + } + + if (BUILD_APP_ENV !== 'opensource') { + const username = initialState?.authList?.username; + const token = `${username}|${initialState?.token}|${new Date().getTime()}`; + const signature = encode(token); + + params.username = username; + params.signature = signature + } + + if (state === 'download_folder') { + params.download = '1'; + params.is_folder = '1' + const downloadUrl = location.origin + `/api/get/oss/url/?` + Object.keys(params).filter((item)=> params[item]).map((key)=> `${key}=${params[key]}`).join('&') + window.open(downloadUrl) + } else { + const data = await request(`/api/get/oss/url/`, { params }) + if (data) { + if (data.code === 200 && data.msg === 'ok') window.open(data.data) + else message.warn(`${['download', 'download_folder'].includes(state) ? formatMessage({ id: 'ws.result.details.failed.download.file' }): formatMessage({ id: 'ws.result.details.failed.get.file' })}`) + } + } + } + const columns = React.useMemo(() => [ { title: 'Test Suite', @@ -179,25 +216,29 @@ const CaseTable: React.FC> = (props) => { showTitle: false, }, render: (_: any, row: any) => ( - editRemarkDrawer.current.show({ - ...row, - suite_name: row.suite_name, - editor_obj: 'test_job_conf' - }) +
+ editRemarkDrawer.current.show({ + ...row, + suite_name: row.suite_name, + editor_obj: 'test_job_conf' + }) + } + /> + {row.conf_log_path && + handlePathClick(row.conf_log_path, 'look')}> {formatMessage({ id: 'operation.log' })} } - /> +
) }, !share_id && ['performance', 'business_performance'].includes(testType) && { title: , width: locale ? 180 : 145, - // fixed: 'right', render: (_: any) => { return ( @@ -302,6 +343,9 @@ const CaseTable: React.FC> = (props) => { expandedRowRender: (record: any) => ( = (props: any) => ( ) -export default ({ test_case_id, suite_id }: any) => { +export default ({ test_case_id, suite_id, confLogInfo }: any) => { const { formatMessage } = useIntl() const { initialState } = useModel('@@initialState') const { id: job_id, share_id } = useParams() as any @@ -95,12 +95,21 @@ export default ({ test_case_id, suite_id }: any) => { } ) + // 默认展开的文件 + // let defaultExpandedKeys = [] + // if (test_case_id === confLogInfo.test_case_id) { + // const str = confLogInfo.conf_log_path || '' + // const folder = str.indexOf('/') > -1 ? str.substring(0, str.lastIndexOf('/')): str + // defaultExpandedKeys = folder.split('/') + // } + return (
{ data.length > 0 ? { const { test_case_id, suite_id, testType, creator, server_provider, state = '', suite_name, conf_name, - refreshId, setRefreshId + refreshId, setRefreshId, lookPathCallback = ()=> {} } = props const editRemark: any = useRef(null) const joinBaseline: any = useRef(null) @@ -259,8 +259,8 @@ export default (props: any) => { !share_id && { title: , - fixed: "right", width: 200, + fixed: "right", render: (_: any, row: any) => { // 失败的 && 没有关联关系的才能“修改基线” const failFlag = _.result === 'Fail' && !row.skip_baseline_info @@ -284,7 +284,20 @@ export default (props: any) => { ) } - } + }, + { + title: , + dataIndex: 'log', + width: 80, + fixed: "right", + ellipsis: true, + render: (_: any, row: any)=> { + const filePath = row.conf_log_path + return filePath ? + lookPathCallback(filePath, 'look') }>{formatMessage({ id: 'operation.log' })} + : null + } + }, ].filter(Boolean) return ( diff --git a/src/pages/WorkSpace/TestResult/Details/TestRsultTable/MetricResultTable.tsx b/src/pages/WorkSpace/TestResult/Details/TestRsultTable/MetricResultTable.tsx index 1f9860fd81bc8e9e3205eee31facfbc305c1d422..1e1b18894987a9fc0359c7f62c7ba46fc67c79cf 100644 --- a/src/pages/WorkSpace/TestResult/Details/TestRsultTable/MetricResultTable.tsx +++ b/src/pages/WorkSpace/TestResult/Details/TestRsultTable/MetricResultTable.tsx @@ -15,7 +15,7 @@ import { MetricSelectProvider } from '.' export default (props: any) => { const { formatMessage } = useIntl() - const { test_case_id, suite_id, state: compare_result, refreshId, setRefreshId, testType } = props + const { test_case_id, suite_id, state: compare_result, refreshId, setRefreshId, testType, lookPathCallback = ()=> {}, } = props const { id: job_id, ws_id, share_id } = useParams() as any const { setOSuite, oSuite } = React.useContext(MetricSelectProvider) const defaultKeys = { @@ -194,6 +194,19 @@ export default (props: any) => { ellipsis: true, render: (_: any, row: any) => compareResultSpan(row.track_result, row.result, formatMessage) }, + { + title: , + dataIndex: 'log', + width: 80, + fixed: "right", + ellipsis: true, + render: (_: any, row: any)=> { + const filePath = row.conf_log_path + return filePath ? + lookPathCallback(filePath, 'look') }>{formatMessage({ id: 'operation.log' })} + : null + } + }, ] const rowSelection: any = !share_id && testType === 'performance' ? { diff --git a/src/pages/WorkSpace/TestResult/Details/TestRsultTable/ResultInfo.tsx b/src/pages/WorkSpace/TestResult/Details/TestRsultTable/ResultInfo.tsx index 72d8807cb0a8d2b370dbf08557672f31e2f316a1..e1cee7580d6414d078ce804e4027ae2c4cf94d86 100644 --- a/src/pages/WorkSpace/TestResult/Details/TestRsultTable/ResultInfo.tsx +++ b/src/pages/WorkSpace/TestResult/Details/TestRsultTable/ResultInfo.tsx @@ -1,5 +1,5 @@ import { Tabs } from 'antd' -import React from 'react' +import React, { useEffect } from 'react' import { isUrl } from '@/utils/utils' import { FormattedMessage } from 'umi' @@ -41,13 +41,21 @@ const ResultInfo: React.FC = (props) => { const ciDetail = ci_detail ? JSON.parse(ci_detail) : {} const [tab, setTab] = React.useState("1") + + // useEffect(()=> { + // // 切换到日志文件tab + // if (confLogInfo.test_case_id && confLogInfo.test_case_id === test_case_id) { + // setTab('3') + // } + // }, [confLogInfo.test_case_id]) + // console.log('ciDetail:', ci_detail); return (
setTab(t)} + onTabClick={(t: any) => setTab(t) } activeKey={tab} /* @ts-ignore */ items={ diff --git a/src/pages/WorkSpace/TestResult/Details/locales/en-US.ts b/src/pages/WorkSpace/TestResult/Details/locales/en-US.ts index 2b54fc827d04269e9f16bb9a3f35c1a95a82955b..13fab7508c7de868b08445491f013837f036b797 100644 --- a/src/pages/WorkSpace/TestResult/Details/locales/en-US.ts +++ b/src/pages/WorkSpace/TestResult/Details/locales/en-US.ts @@ -55,7 +55,7 @@ const text = { 'tab.testProgress': 'Cases', 'tab.testConfig': 'Test Configurations', 'tab.monitor': 'Data Monitor', - 'tab.log': 'Logs', + 'tab.log': 'Log Details', 'tab.resultFile': 'Result File', 'tab.versionInfo': 'Version Info', 'tab.executionDetails': 'Execution Details', diff --git a/src/pages/WorkSpace/TestResult/Details/locales/zh-CN.ts b/src/pages/WorkSpace/TestResult/Details/locales/zh-CN.ts index a8de80ed6472ed9b42a60b41af312cfb31df74c6..c94fc3e33bad9b5840a3e4e4c337b7194c83b6a2 100644 --- a/src/pages/WorkSpace/TestResult/Details/locales/zh-CN.ts +++ b/src/pages/WorkSpace/TestResult/Details/locales/zh-CN.ts @@ -50,7 +50,7 @@ const text = { 'tab.testProgress': '执行过程', 'tab.testConfig': '测试配置', 'tab.monitor': '数据监控', - 'tab.log': '日志文件', + 'tab.log': '日志详情', 'tab.resultFile': '结果文件', 'tab.versionInfo': '版本信息', 'tab.executionDetails': '执行详情', diff --git a/src/services/Workspace.ts b/src/services/Workspace.ts index 9b2585f6617c0ab9f52d94317bb57258b0f55fa9..c3b469c7be9e69598366705fbf56b85677a2ca7a 100644 --- a/src/services/Workspace.ts +++ b/src/services/Workspace.ts @@ -7,6 +7,8 @@ export async function queryWorkspace(params: any) { export async function queryWorkspaceHistory(params?: any) { return request('/api/sys/workspace/history/', { params }) } + +// 对比分析获取垮ws的ws集合接口改用这个 export async function queryHomeWorkspace(params: any) { return request('/api/sys/workspace/list/', { params }) } diff --git a/src/utils/hooks.tsx b/src/utils/hooks.tsx index 61198b72c95a4697300bda83478cfc4f8746cecb..d06795f8ff610efd9853b0b32a451393438b85cd 100644 --- a/src/utils/hooks.tsx +++ b/src/utils/hooks.tsx @@ -10,7 +10,7 @@ const { document, location }: any = window export const enterWsAndGetList = async (ws_id: any) => { try { - const { data } = await enterWorkspaceHistroy({ ws_id }) + const { data } = await enterWorkspaceHistroy({ ws_id }) || {} const { code, ...historyWorkspaces } = await queryWorkspaceHistory({ page_num: 1, page_size: 20, diff --git a/src/wrappers/WorkspaceAuth.tsx b/src/wrappers/WorkspaceAuth.tsx index 32da761a4a1a93bee935448f156ce6def559f66b..af06f33e3041a0778b9cc90c65f7790f00595bf5 100644 --- a/src/wrappers/WorkspaceAuth.tsx +++ b/src/wrappers/WorkspaceAuth.tsx @@ -29,7 +29,7 @@ export default (props: any) => { /* 切换ws请求记录历史接口 */ /* getHistoryFetcher() */ - const ws = await enterWsAndGetList(ws_id) + const ws = await enterWsAndGetList(ws_id) || {} setInitialState((p: any) => ({ ...p, ...ws,