fix(全局): bug修复&devLocalEnv
This commit is contained in:
parent
8965678a2c
commit
95eb0aa49e
|
@ -1 +1,2 @@
|
||||||
VITE_API_BASE_URL= 'front'
|
VITE_API_BASE_URL= 'front'
|
||||||
|
VITE_DEV_DOMAIN='http://172.16.200.18:8081/'
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
/// <reference types="vitest" />
|
/// <reference types="vitest" />
|
||||||
import baseConfig from './vite.config.base';
|
import baseConfig from './vite.config.base';
|
||||||
|
import dotenv from 'dotenv';
|
||||||
import { mergeConfig } from 'vite';
|
import { mergeConfig } from 'vite';
|
||||||
import eslint from 'vite-plugin-eslint';
|
import eslint from 'vite-plugin-eslint';
|
||||||
|
|
||||||
|
// 注入本地/开发配置环境变量(先导入的配置优先级高)
|
||||||
|
dotenv.config({ path: ['.env.development.local', '.env.development'] });
|
||||||
|
|
||||||
export default mergeConfig(
|
export default mergeConfig(
|
||||||
{
|
{
|
||||||
mode: 'development',
|
mode: 'development',
|
||||||
|
@ -13,38 +17,38 @@ export default mergeConfig(
|
||||||
},
|
},
|
||||||
proxy: {
|
proxy: {
|
||||||
'/ws': {
|
'/ws': {
|
||||||
target: 'http://172.16.200.18:8081/',
|
target: process.env.VITE_DEV_DOMAIN,
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path: string) => path.replace(/^\/front\/ws/, ''),
|
rewrite: (path: string) => path.replace(/^\/front\/ws/, ''),
|
||||||
ws: true,
|
ws: true,
|
||||||
},
|
},
|
||||||
'/front': {
|
'/front': {
|
||||||
target: 'http://172.16.200.18:8081/',
|
target: process.env.VITE_DEV_DOMAIN,
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path: string) => path.replace(/^\/front/, ''),
|
rewrite: (path: string) => path.replace(/^\/front/, ''),
|
||||||
},
|
},
|
||||||
'/file': {
|
'/file': {
|
||||||
target: 'http://172.16.200.18:8081/',
|
target: process.env.VITE_DEV_DOMAIN,
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path: string) => path.replace(/^\/front\/file/, ''),
|
rewrite: (path: string) => path.replace(/^\/front\/file/, ''),
|
||||||
},
|
},
|
||||||
'/attachment': {
|
'/attachment': {
|
||||||
target: 'http://172.16.200.18:8081/',
|
target: process.env.VITE_DEV_DOMAIN,
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path: string) => path.replace(/^\/front\/attachment/, ''),
|
rewrite: (path: string) => path.replace(/^\/front\/attachment/, ''),
|
||||||
},
|
},
|
||||||
'/bug/attachment': {
|
'/bug/attachment': {
|
||||||
target: 'http://172.16.200.18:8081/',
|
target: process.env.VITE_DEV_DOMAIN,
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path: string) => path.replace(/^\/front\/bug\/attachment/, ''),
|
rewrite: (path: string) => path.replace(/^\/front\/bug\/attachment/, ''),
|
||||||
},
|
},
|
||||||
'/plugin/image': {
|
'/plugin/image': {
|
||||||
target: 'http://172.16.200.18:8081/',
|
target: process.env.VITE_DEV_DOMAIN,
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path: string) => path.replace(/^\/front\/plugin\/image/, ''),
|
rewrite: (path: string) => path.replace(/^\/front\/plugin\/image/, ''),
|
||||||
},
|
},
|
||||||
'/base-display': {
|
'/base-display': {
|
||||||
target: 'http://172.16.200.18:8081/',
|
target: process.env.VITE_DEV_DOMAIN,
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path: string) => path.replace(/^\/front\/base-display/, ''),
|
rewrite: (path: string) => path.replace(/^\/front\/base-display/, ''),
|
||||||
},
|
},
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
"ahooks-vue": "^0.15.1",
|
"ahooks-vue": "^0.15.1",
|
||||||
"axios": "^1.6.5",
|
"axios": "^1.6.5",
|
||||||
"dayjs": "^1.11.9",
|
"dayjs": "^1.11.9",
|
||||||
|
"dotenv": "^16.4.5",
|
||||||
"echarts": "^5.4.3",
|
"echarts": "^5.4.3",
|
||||||
"fastq": "^1.15.0",
|
"fastq": "^1.15.0",
|
||||||
"github-markdown-css": "^5.5.1",
|
"github-markdown-css": "^5.5.1",
|
||||||
|
|
|
@ -32,8 +32,6 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
|
||||||
|
|
||||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||||
import { MsTableColumn } from '@/components/pure/ms-table/type';
|
import { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||||
|
|
|
@ -69,6 +69,7 @@
|
||||||
import { FormItem } from '@/components/pure/ms-form-create/types';
|
import { FormItem } from '@/components/pure/ms-form-create/types';
|
||||||
import MsMinderEditor from '@/components/pure/ms-minder-editor/minderEditor.vue';
|
import MsMinderEditor from '@/components/pure/ms-minder-editor/minderEditor.vue';
|
||||||
import type { MinderJson, MinderJsonNode, MinderJsonNodeData } from '@/components/pure/ms-minder-editor/props';
|
import type { MinderJson, MinderJsonNode, MinderJsonNodeData } from '@/components/pure/ms-minder-editor/props';
|
||||||
|
import { setPriorityView } from '@/components/pure/ms-minder-editor/script/tool/utils';
|
||||||
import { MsFileItem } from '@/components/pure/ms-upload/types';
|
import { MsFileItem } from '@/components/pure/ms-upload/types';
|
||||||
import attachment from './attachment.vue';
|
import attachment from './attachment.vue';
|
||||||
import baseInfo from './basInfo.vue';
|
import baseInfo from './basInfo.vue';
|
||||||
|
@ -87,7 +88,7 @@
|
||||||
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
||||||
import useMinderStore from '@/store/modules/components/minder-editor/index';
|
import useMinderStore from '@/store/modules/components/minder-editor/index';
|
||||||
import { MinderCustomEvent } from '@/store/modules/components/minder-editor/types';
|
import { MinderCustomEvent } from '@/store/modules/components/minder-editor/types';
|
||||||
import { filterTree, getGenerateId, mapTree } from '@/utils';
|
import { filterTree, getGenerateId, mapTree, replaceNodeInTree } from '@/utils';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FeatureCaseMinderEditType,
|
FeatureCaseMinderEditType,
|
||||||
|
@ -158,7 +159,7 @@
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const res = await getCaseMinderTree({
|
const res = await getCaseMinderTree({
|
||||||
projectId: appStore.currentProjectId,
|
projectId: appStore.currentProjectId,
|
||||||
moduleId: props.moduleId === 'all' ? '' : props.moduleId,
|
moduleId: '', // 始终加载全部,然后再进入对应的模块节点
|
||||||
});
|
});
|
||||||
caseTree.value = mapTree<MinderJsonNode>(res, (e) => ({
|
caseTree.value = mapTree<MinderJsonNode>(res, (e) => ({
|
||||||
...e,
|
...e,
|
||||||
|
@ -195,8 +196,11 @@
|
||||||
disabled: true,
|
disabled: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
importJson.value.treePath = [];
|
||||||
window.minder.importJson(importJson.value);
|
window.minder.importJson(importJson.value);
|
||||||
|
window.minder.execCommand('camera', window.minder.getRoot(), 100);
|
||||||
if (props.moduleId !== 'all') {
|
if (props.moduleId !== 'all') {
|
||||||
|
// 携带具体的模块 ID 加载时,进入该模块内
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
minderStore.dispatchEvent(MinderEventName.ENTER_NODE, undefined, undefined, undefined, [
|
minderStore.dispatchEvent(MinderEventName.ENTER_NODE, undefined, undefined, undefined, [
|
||||||
window.minder.getNodeById(props.moduleId),
|
window.minder.getNodeById(props.moduleId),
|
||||||
|
@ -485,7 +489,15 @@
|
||||||
node.data.isLoaded = true;
|
node.data.isLoaded = true;
|
||||||
}
|
}
|
||||||
// 加载完用例数据后,更新当前importJson数据
|
// 加载完用例数据后,更新当前importJson数据
|
||||||
importJson.value = window.minder.exportJson();
|
const currentFullJson: MinderJson = window.minder.exportJson();
|
||||||
|
const { root } = currentFullJson;
|
||||||
|
if (root.data?.id === 'NONE') {
|
||||||
|
// 当前仍然是全部模块视图,则直接替换
|
||||||
|
importJson.value = currentFullJson;
|
||||||
|
} else {
|
||||||
|
// 当前是单个模块视图,则替换对应模块的数据
|
||||||
|
replaceNodeInTree([importJson.value.root], node.data?.id || '', root, 'data', 'id');
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
@ -503,6 +515,7 @@
|
||||||
window.minder.layout();
|
window.minder.layout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setPriorityView(true, 'P');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
associationType: CaseLinkEnum;
|
||||||
hasNotAssociatedIds?: string[];
|
hasNotAssociatedIds?: string[];
|
||||||
saveApi?: (params: AssociateCaseRequestType) => Promise<any>;
|
saveApi?: (params: AssociateCaseRequestType) => Promise<any>;
|
||||||
testPlanId?: string;
|
testPlanId?: string;
|
||||||
|
@ -73,7 +74,4 @@
|
||||||
}
|
}
|
||||||
innerVisible.value = false;
|
innerVisible.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO 关联用例脑图待替换关联类型
|
|
||||||
const associationType = ref<keyof typeof CaseLinkEnum>('FUNCTIONAL');
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -224,7 +224,7 @@
|
||||||
</MsMinderEditor>
|
</MsMinderEditor>
|
||||||
<caseAssociate
|
<caseAssociate
|
||||||
v-model:visible="caseAssociateVisible"
|
v-model:visible="caseAssociateVisible"
|
||||||
v-model:currentSelectCase="currentSelectCase"
|
:association-type="currentSelectCase"
|
||||||
:has-not-associated-ids="selectedAssociateCasesParams.selectIds"
|
:has-not-associated-ids="selectedAssociateCasesParams.selectIds"
|
||||||
:test-plan-id="props.planId"
|
:test-plan-id="props.planId"
|
||||||
@success="writeAssociateCases"
|
@success="writeAssociateCases"
|
||||||
|
@ -269,6 +269,9 @@
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
planId: string;
|
planId: string;
|
||||||
}>();
|
}>();
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'save'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -373,6 +376,7 @@
|
||||||
text: t('ms.minders.item', { count: 0 }),
|
text: t('ms.minders.item', { count: 0 }),
|
||||||
resource: [caseCountTag],
|
resource: [caseCountTag],
|
||||||
level: 3,
|
level: 3,
|
||||||
|
disabled: true, // 只有测试集能改文本
|
||||||
isNew: true,
|
isNew: true,
|
||||||
};
|
};
|
||||||
// 环境子节点
|
// 环境子节点
|
||||||
|
@ -381,6 +385,7 @@
|
||||||
text: t('case.execute.defaultEnv'),
|
text: t('case.execute.defaultEnv'),
|
||||||
resource: [envTag],
|
resource: [envTag],
|
||||||
level: 3,
|
level: 3,
|
||||||
|
disabled: true, // 只有测试集能改文本
|
||||||
isNew: true,
|
isNew: true,
|
||||||
};
|
};
|
||||||
// 资源池子节点
|
// 资源池子节点
|
||||||
|
@ -389,6 +394,7 @@
|
||||||
resource: [resourcePoolTag],
|
resource: [resourcePoolTag],
|
||||||
text: t('ms.minders.defaultResourcePool'),
|
text: t('ms.minders.defaultResourcePool'),
|
||||||
level: 3,
|
level: 3,
|
||||||
|
disabled: true, // 只有测试集能改文本
|
||||||
isNew: true,
|
isNew: true,
|
||||||
};
|
};
|
||||||
if (node.data?.level === 1) {
|
if (node.data?.level === 1) {
|
||||||
|
@ -398,6 +404,7 @@
|
||||||
id: getGenerateId(),
|
id: getGenerateId(),
|
||||||
text: t('ms.minders.defaultTestSet'),
|
text: t('ms.minders.defaultTestSet'),
|
||||||
level: 2,
|
level: 2,
|
||||||
|
disabled: false, // 只有测试集能改文本
|
||||||
isNew: true,
|
isNew: true,
|
||||||
};
|
};
|
||||||
} else if (node.parent?.data) {
|
} else if (node.parent?.data) {
|
||||||
|
@ -407,6 +414,7 @@
|
||||||
id: getGenerateId(),
|
id: getGenerateId(),
|
||||||
text: t('ms.minders.defaultTestSet'),
|
text: t('ms.minders.defaultTestSet'),
|
||||||
level: 2,
|
level: 2,
|
||||||
|
disabled: false, // 只有测试集能改文本
|
||||||
isNew: true,
|
isNew: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -545,7 +553,7 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentSelectCase = ref<keyof typeof CaseLinkEnum>('FUNCTIONAL');
|
const currentSelectCase = ref<CaseLinkEnum>(CaseLinkEnum.FUNCTIONAL);
|
||||||
const caseAssociateVisible = ref<boolean>(false);
|
const caseAssociateVisible = ref<boolean>(false);
|
||||||
|
|
||||||
// 批量关联用例表格参数
|
// 批量关联用例表格参数
|
||||||
|
@ -592,7 +600,7 @@
|
||||||
switchingConfigFormData.value = true;
|
switchingConfigFormData.value = true;
|
||||||
configForm.value = cloneDeep(activePlanSet.value.data);
|
configForm.value = cloneDeep(activePlanSet.value.data);
|
||||||
extraVisible.value = true;
|
extraVisible.value = true;
|
||||||
currentSelectCase.value = node.data?.type || 'FUNCTIONAL';
|
currentSelectCase.value = (node.data?.type as unknown as CaseLinkEnum) || CaseLinkEnum.FUNCTIONAL;
|
||||||
caseAssociateVisible.value = true;
|
caseAssociateVisible.value = true;
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
switchingConfigFormData.value = false;
|
switchingConfigFormData.value = false;
|
||||||
|
@ -671,7 +679,7 @@
|
||||||
level,
|
level,
|
||||||
isNew: false,
|
isNew: false,
|
||||||
changed: false,
|
changed: false,
|
||||||
disabled: level < 2,
|
disabled: level !== 2, // 只有测试集能改文本
|
||||||
};
|
};
|
||||||
return node;
|
return node;
|
||||||
});
|
});
|
||||||
|
@ -727,6 +735,7 @@
|
||||||
handleConfigCancel();
|
handleConfigCancel();
|
||||||
initMinder();
|
initMinder();
|
||||||
callback();
|
callback();
|
||||||
|
emit('save');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
<slot name="title" v-bind="_props"></slot>
|
<slot name="title" v-bind="_props"></slot>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="$slots['extra'] || props.nodeMoreActions" #extra="_props">
|
<template v-if="$slots['extra'] || props.nodeMoreActions" #extra="_props">
|
||||||
<div class="sticky right-[8px] flex items-center justify-between">
|
<div class="sticky right-0 flex items-center justify-between">
|
||||||
<div v-if="_props.hideMoreAction !== true" class="ms-tree-node-extra">
|
<div v-if="_props.hideMoreAction !== true" class="ms-tree-node-extra">
|
||||||
<slot name="extra" v-bind="_props"></slot>
|
<slot name="extra" v-bind="_props"></slot>
|
||||||
<MsTableMoreAction
|
<MsTableMoreAction
|
||||||
|
@ -497,6 +497,7 @@
|
||||||
@apply invisible flex w-0 items-center;
|
@apply invisible flex w-0 items-center;
|
||||||
|
|
||||||
margin-left: -4px;
|
margin-left: -4px;
|
||||||
|
padding-right: 8px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
border-radius: var(--border-radius-small);
|
border-radius: var(--border-radius-small);
|
||||||
background-color: rgb(var(--primary-1));
|
background-color: rgb(var(--primary-1));
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
<minderHeader :icon-buttons="props.iconButtons" @save="save" />
|
<minderHeader :icon-buttons="props.iconButtons" @save="save" />
|
||||||
<Navigator />
|
<Navigator />
|
||||||
<div
|
<div
|
||||||
v-if="innerImportJson.treePath?.length > 1"
|
v-if="currentTreePath?.length > 0"
|
||||||
class="absolute left-[50%] top-[24px] z-50 translate-x-[-50%] bg-white p-[8px]"
|
class="absolute left-[50%] top-[24px] z-50 translate-x-[-50%] bg-white p-[8px]"
|
||||||
>
|
>
|
||||||
<a-breadcrumb>
|
<a-breadcrumb>
|
||||||
<a-breadcrumb-item v-for="crumb of innerImportJson.treePath" :key="crumb.name" @click="switchNode(crumb)">
|
<a-breadcrumb-item v-for="crumb of currentTreePath" :key="crumb.name" @click="switchNode(crumb)">
|
||||||
{{ crumb.text }}
|
{{ crumb.text }}
|
||||||
</a-breadcrumb-item>
|
</a-breadcrumb-item>
|
||||||
</a-breadcrumb>
|
</a-breadcrumb>
|
||||||
|
@ -80,6 +80,7 @@
|
||||||
template: 'default',
|
template: 'default',
|
||||||
treePath: [],
|
treePath: [],
|
||||||
});
|
});
|
||||||
|
const currentTreePath = ref<MinderJsonNodeData[]>([]);
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
window.editor = new Editor(mec.value, {
|
window.editor = new Editor(mec.value, {
|
||||||
|
@ -144,6 +145,14 @@
|
||||||
const menuVisible = ref(false);
|
const menuVisible = ref(false);
|
||||||
const menuPopupOffset = ref([0, 0]);
|
const menuPopupOffset = ref([0, 0]);
|
||||||
|
|
||||||
|
function getCurrentTreePath() {
|
||||||
|
if (innerImportJson.value.root.id === 'NONE' || innerImportJson.value.treePath?.length <= 1) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const index = innerImportJson.value.treePath?.findIndex((e) => e.id === innerImportJson.value.root.data?.id);
|
||||||
|
return innerImportJson.value.treePath?.filter((e, i) => i <= index) || [];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 切换脑图展示的节点层级
|
* 切换脑图展示的节点层级
|
||||||
* @param node 切换的节点
|
* @param node 切换的节点
|
||||||
|
@ -159,15 +168,20 @@
|
||||||
'id'
|
'id'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (node.data) {
|
if (node.id === 'NONE') {
|
||||||
|
innerImportJson.value = importJson.value;
|
||||||
|
} else if (node.data) {
|
||||||
innerImportJson.value = findNodePathByKey([importJson.value.root], node.data.id, 'data', 'id') as MinderJson;
|
innerImportJson.value = findNodePathByKey([importJson.value.root], node.data.id, 'data', 'id') as MinderJson;
|
||||||
} else {
|
} else {
|
||||||
innerImportJson.value = findNodePathByKey([importJson.value.root], node.id, 'data', 'id') as MinderJson;
|
innerImportJson.value = findNodePathByKey([importJson.value.root], node.id, 'data', 'id') as MinderJson;
|
||||||
}
|
}
|
||||||
window.minder.importJson(innerImportJson.value);
|
window.minder.importJson(innerImportJson.value);
|
||||||
|
const root: MinderJsonNode = window.minder.getRoot();
|
||||||
|
window.minder.toggleSelect(root); // 先取消选中
|
||||||
|
window.minder.select(root); // 再选中,才能触发选中变化事件
|
||||||
|
currentTreePath.value = getCurrentTreePath();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.minder.select(window.minder.getRoot());
|
window.minder.execCommand('camera', root);
|
||||||
window.minder.execCommand('camera', window.minder.getRoot());
|
|
||||||
}, 100); // TODO:暂未知渲染时机,临时延迟解决
|
}, 100); // TODO:暂未知渲染时机,临时延迟解决
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,6 +234,13 @@
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => importJson.value.treePath,
|
||||||
|
(arr) => {
|
||||||
|
currentTreePath.value = arr;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
minderStore.setMinderUnsaved(false);
|
minderStore.setMinderUnsaved(false);
|
||||||
});
|
});
|
||||||
|
|
|
@ -97,7 +97,9 @@
|
||||||
(val) => {
|
(val) => {
|
||||||
const node: MinderJsonNode = window.minder.getSelectedNode();
|
const node: MinderJsonNode = window.minder.getSelectedNode();
|
||||||
if (val && node) {
|
if (val && node) {
|
||||||
window.minder.execCommand('camera', node, 100);
|
nextTick(() => {
|
||||||
|
window.minder.execCommand('camera', node, 100);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -36,7 +36,7 @@ export interface MinderJsonNode {
|
||||||
export interface MinderJson {
|
export interface MinderJson {
|
||||||
root: MinderJsonNode;
|
root: MinderJsonNode;
|
||||||
template: string;
|
template: string;
|
||||||
treePath: MinderJsonNode[];
|
treePath: MinderJsonNodeData[];
|
||||||
}
|
}
|
||||||
// 脑图类
|
// 脑图类
|
||||||
export interface MinderClass {
|
export interface MinderClass {
|
||||||
|
|
|
@ -62,6 +62,13 @@
|
||||||
// 临时值,用于组件内部变更,但未影响到实际值
|
// 临时值,用于组件内部变更,但未影响到实际值
|
||||||
const tempActiveKey = ref(activeKey.value);
|
const tempActiveKey = ref(activeKey.value);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => activeKey.value,
|
||||||
|
(val) => {
|
||||||
|
tempActiveKey.value = val;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
function handleTabClick(value: string) {
|
function handleTabClick(value: string) {
|
||||||
if (value === activeKey.value) {
|
if (value === activeKey.value) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -32,11 +32,11 @@ export default {
|
||||||
'asyncTask.uploadFileSuccessTitle': 'Upload completed',
|
'asyncTask.uploadFileSuccessTitle': 'Upload completed',
|
||||||
// 通用业务提示
|
// 通用业务提示
|
||||||
'user.openSourceCreateUsersLimit':
|
'user.openSourceCreateUsersLimit':
|
||||||
'The maximum number of system users has reached 30 (Community Edition). If you need to add more users, you can apply',
|
'The maximum number of system users has reached 30 (Community Edition). If you need to add/enable more users, you can apply',
|
||||||
'user.businessTry': 'Enterprise Edition Trial',
|
'user.businessTry': 'Enterprise Edition Trial',
|
||||||
'user.businessCreateUsersLimitThirty':
|
'user.businessCreateUsersLimitThirty':
|
||||||
'The maximum number of system users has reached 30 (Community Edition). If you need to add more users, you can apply',
|
'The maximum number of system users has reached 30 (Community Edition). If you need to add/enable more users, you can apply',
|
||||||
'user.businessCreateUsersLimitMax':
|
'user.businessCreateUsersLimitMax':
|
||||||
'The number of system users has reached the maximum number of user subscriptions {count}. If you want to add more users, you can apply',
|
'The number of system users has reached the maximum number of user subscriptions {count}. If you want to add/enable more users, you can apply',
|
||||||
'user.businessScaling': 'Enterprise Edition Capacity Expansion',
|
'user.businessScaling': 'Enterprise Edition Capacity Expansion',
|
||||||
};
|
};
|
||||||
|
|
|
@ -31,9 +31,9 @@ export default {
|
||||||
'asyncTask.uploadFileSuccess': '文件上传完成:成功 {done} 个,失败 {fail} 个',
|
'asyncTask.uploadFileSuccess': '文件上传完成:成功 {done} 个,失败 {fail} 个',
|
||||||
'asyncTask.uploadFileSuccessTitle': '上传完成',
|
'asyncTask.uploadFileSuccessTitle': '上传完成',
|
||||||
// 通用业务提示
|
// 通用业务提示
|
||||||
'user.openSourceCreateUsersLimit': '系统用户数已达到最大用户数限制30人(社区版),如需添加更多用户,可申请',
|
'user.openSourceCreateUsersLimit': '系统用户数已达到最大用户数限制30人(社区版),如需添加/启用更多用户,可申请',
|
||||||
'user.businessTry': '企业版试用',
|
'user.businessTry': '企业版试用',
|
||||||
'user.businessCreateUsersLimitThirty': '系统用户数已达到最大用户数限制30人 (社区版),如需添加更多用户,可申请',
|
'user.businessCreateUsersLimitThirty': '系统用户数已达到最大用户数限制30人 (社区版),如需添加/启用更多用户,可申请',
|
||||||
'user.businessCreateUsersLimitMax': '系统用户数已达到最大用户订阅数 {count} 人,如需添加更多用户,可申请',
|
'user.businessCreateUsersLimitMax': '系统用户数已达到最大用户订阅数 {count} 人,如需添加/启用更多用户,可申请',
|
||||||
'user.businessScaling': '企业版扩容',
|
'user.businessScaling': '企业版扩容',
|
||||||
};
|
};
|
||||||
|
|
|
@ -255,7 +255,6 @@
|
||||||
</template>
|
</template>
|
||||||
<!-- SQL操作 -->
|
<!-- SQL操作 -->
|
||||||
<template v-else-if="condition.processorType === RequestConditionProcessor.SQL">
|
<template v-else-if="condition.processorType === RequestConditionProcessor.SQL">
|
||||||
<div class="mb-[8px] text-[var(--color-text-1)]">{{ t('ms.paramsInput.sqlOperationNameDesc') }}</div>
|
|
||||||
<div class="mb-[8px]">
|
<div class="mb-[8px]">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:model-value="condition.name"
|
v-model:model-value="condition.name"
|
||||||
|
|
|
@ -1164,6 +1164,20 @@
|
||||||
requestVModel.value.executeLoading = false;
|
requestVModel.value.executeLoading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setDefaultActiveTab() {
|
||||||
|
if (requestVModel.value.body.bodyType !== RequestBodyFormat.NONE) {
|
||||||
|
requestVModel.value.activeTab = RequestComposition.BODY;
|
||||||
|
} else if (requestVModel.value.query.length > 0) {
|
||||||
|
requestVModel.value.activeTab = RequestComposition.QUERY;
|
||||||
|
} else if (requestVModel.value.rest.length > 0) {
|
||||||
|
requestVModel.value.activeTab = RequestComposition.REST;
|
||||||
|
} else if (requestVModel.value.headers.length > 0) {
|
||||||
|
requestVModel.value.activeTab = RequestComposition.HEADER;
|
||||||
|
} else {
|
||||||
|
requestVModel.value.activeTab = RequestComposition.BODY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => requestVModel.value.id,
|
() => requestVModel.value.id,
|
||||||
async () => {
|
async () => {
|
||||||
|
@ -1189,6 +1203,7 @@
|
||||||
// 如果定义有参数BODY/QUERY/REST,用例默认tab是参数tab
|
// 如果定义有参数BODY/QUERY/REST,用例默认tab是参数tab
|
||||||
requestVModel.value.activeTab = contentTabList.value[1].value;
|
requestVModel.value.activeTab = contentTabList.value[1].value;
|
||||||
}
|
}
|
||||||
|
setDefaultActiveTab();
|
||||||
if (!props.isCase) {
|
if (!props.isCase) {
|
||||||
responseRef.value?.setActiveResponse(requestVModel.value.mode === 'debug' ? 'result' : 'content');
|
responseRef.value?.setActiveResponse(requestVModel.value.mode === 'debug' ? 'result' : 'content');
|
||||||
}
|
}
|
||||||
|
|
|
@ -233,6 +233,7 @@
|
||||||
...cloneDeep(defaultDebugParams),
|
...cloneDeep(defaultDebugParams),
|
||||||
id,
|
id,
|
||||||
isNew: !defaultProps?.id, // 新开的tab标记为前端新增的调试,因为此时都已经有id了;但是如果是查看打开的会有携带id
|
isNew: !defaultProps?.id, // 新开的tab标记为前端新增的调试,因为此时都已经有id了;但是如果是查看打开的会有携带id
|
||||||
|
protocol: activeDebug.value.protocol, // 新开的tab默认使用当前激活的tab的协议
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
});
|
});
|
||||||
activeDebug.value = debugTabs.value[debugTabs.value.length - 1];
|
activeDebug.value = debugTabs.value[debugTabs.value.length - 1];
|
||||||
|
|
|
@ -202,7 +202,7 @@ export default {
|
||||||
'apiTestDebug.searchByDataBaseName': 'Search by data source name',
|
'apiTestDebug.searchByDataBaseName': 'Search by data source name',
|
||||||
'apiTestDebug.regexMatchRules': 'Expression matching rules',
|
'apiTestDebug.regexMatchRules': 'Expression matching rules',
|
||||||
'apiTestDebug.extractValueTitleTip':
|
'apiTestDebug.extractValueTitleTip':
|
||||||
'Enter the column name and corresponding value in column storage. If you want to extract the first value of the name column, enter name_1',
|
'Enter the column name and corresponding value in column storage. If you want to extract the first value of the id column, enter id_1',
|
||||||
'apiTestDebug.responseRepeatMessage': 'The name is duplicated, please re-enter it.',
|
'apiTestDebug.responseRepeatMessage': 'The name is duplicated, please re-enter it.',
|
||||||
'apiTestDebug.saveAsApi': 'Save as Api',
|
'apiTestDebug.saveAsApi': 'Save as Api',
|
||||||
'apiTestDebug.assertionItem': 'Assertion item',
|
'apiTestDebug.assertionItem': 'Assertion item',
|
||||||
|
|
|
@ -188,7 +188,7 @@ export default {
|
||||||
'apiTestDebug.testSuccess': '测试成功',
|
'apiTestDebug.testSuccess': '测试成功',
|
||||||
'apiTestDebug.searchByDataBaseName': '按数据源名称搜索',
|
'apiTestDebug.searchByDataBaseName': '按数据源名称搜索',
|
||||||
'apiTestDebug.regexMatchRules': '表达式匹配规则',
|
'apiTestDebug.regexMatchRules': '表达式匹配规则',
|
||||||
'apiTestDebug.extractValueTitleTip': '输入按列存储中的列名和对应的数值,如提取name列的第一个值则输入name_1',
|
'apiTestDebug.extractValueTitleTip': '输入按列存储中的列名和对应的数值,如提取 id 列的第一个值则输入 id_1',
|
||||||
'apiTestDebug.responseRepeatMessage': '名称重复,请重新输入',
|
'apiTestDebug.responseRepeatMessage': '名称重复,请重新输入',
|
||||||
'apiTestDebug.saveAsApi': '另存为接口',
|
'apiTestDebug.saveAsApi': '另存为接口',
|
||||||
'apiTestDebug.assertionItem': '断言项',
|
'apiTestDebug.assertionItem': '断言项',
|
||||||
|
|
|
@ -306,6 +306,7 @@
|
||||||
id,
|
id,
|
||||||
isNew: !defaultProps?.id, // 新开的tab标记为前端新增的调试,因为此时都已经有id了;但是如果是查看打开的会有携带id
|
isNew: !defaultProps?.id, // 新开的tab标记为前端新增的调试,因为此时都已经有id了;但是如果是查看打开的会有携带id
|
||||||
definitionActiveKey: !defaultProps ? 'definition' : 'preview',
|
definitionActiveKey: !defaultProps ? 'definition' : 'preview',
|
||||||
|
protocol: activeApiTab.value.protocol, // 新开的tab默认使用当前激活的tab的协议
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
});
|
});
|
||||||
activeApiTab.value = apiTabs.value[apiTabs.value.length - 1];
|
activeApiTab.value = apiTabs.value[apiTabs.value.length - 1];
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
@close="handleClose"
|
@close="handleClose"
|
||||||
>
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="flex max-w-[60%] items-center gap-[8px]">
|
<div class="flex flex-1 items-center gap-[8px] overflow-hidden">
|
||||||
<div
|
<div
|
||||||
v-if="props.step"
|
v-if="props.step"
|
||||||
class="flex h-[16px] min-w-[16px] items-center justify-center rounded-full bg-[var(--color-text-brand)] pr-[2px] !text-white"
|
class="flex h-[16px] min-w-[16px] items-center justify-center rounded-full bg-[var(--color-text-brand)] pr-[2px] !text-white"
|
||||||
|
@ -26,30 +26,30 @@
|
||||||
:step="props.step"
|
:step="props.step"
|
||||||
/>
|
/>
|
||||||
<a-tooltip v-if="!isShowEditStepNameInput" :content="title" position="bottom">
|
<a-tooltip v-if="!isShowEditStepNameInput" :content="title" position="bottom">
|
||||||
<div class="flex items-center gap-[4px]">
|
<div class="flex flex-1 items-center gap-[4px] overflow-hidden">
|
||||||
<div class="one-line-text max-w-[300px]">
|
<div class="one-line-text">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</div>
|
</div>
|
||||||
<MsIcon
|
<MsIcon
|
||||||
v-if="!props.step || !props.step.isQuoteScenarioStep"
|
v-if="!props.step || !props.step.isQuoteScenarioStep"
|
||||||
type="icon-icon_edit_outlined"
|
type="icon-icon_edit_outlined"
|
||||||
class="cursor-pointer hover:text-[rgb(var(--primary-5))]"
|
class="min-w-[16px] cursor-pointer hover:text-[rgb(var(--primary-5))]"
|
||||||
@click="isShowEditStepNameInput = true"
|
@click="isShowEditStepNameInput = true"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
|
<a-input
|
||||||
|
v-if="isShowEditStepNameInput"
|
||||||
|
ref="stepNameInputRef"
|
||||||
|
v-model:model-value="requestVModel.stepName"
|
||||||
|
class="flex-1"
|
||||||
|
:placeholder="t('apiScenario.pleaseInputStepName')"
|
||||||
|
:max-length="255"
|
||||||
|
show-word-limit
|
||||||
|
@press-enter="updateStepName"
|
||||||
|
@blur="updateStepName"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<a-input
|
|
||||||
v-if="isShowEditStepNameInput"
|
|
||||||
ref="stepNameInputRef"
|
|
||||||
v-model:model-value="requestVModel.stepName"
|
|
||||||
class="flex-1"
|
|
||||||
:placeholder="t('apiScenario.pleaseInputStepName')"
|
|
||||||
:max-length="255"
|
|
||||||
show-word-limit
|
|
||||||
@press-enter="updateStepName"
|
|
||||||
@blur="updateStepName"
|
|
||||||
/>
|
|
||||||
<div v-show="!isShowEditStepNameInput" class="ml-auto flex items-center gap-[16px]">
|
<div v-show="!isShowEditStepNameInput" class="ml-auto flex items-center gap-[16px]">
|
||||||
<div
|
<div
|
||||||
v-if="!props.step || props.step?.stepType === ScenarioStepType.CUSTOM_REQUEST"
|
v-if="!props.step || props.step?.stepType === ScenarioStepType.CUSTOM_REQUEST"
|
||||||
|
@ -1156,6 +1156,20 @@
|
||||||
// const showAddDependencyDrawer = ref(false);
|
// const showAddDependencyDrawer = ref(false);
|
||||||
// const addDependencyMode = ref<'pre' | 'post'>('pre');
|
// const addDependencyMode = ref<'pre' | 'post'>('pre');
|
||||||
|
|
||||||
|
function setDefaultActiveTab() {
|
||||||
|
if (requestVModel.value.body.bodyType !== RequestBodyFormat.NONE) {
|
||||||
|
requestVModel.value.activeTab = RequestComposition.BODY;
|
||||||
|
} else if (requestVModel.value.query.length > 0) {
|
||||||
|
requestVModel.value.activeTab = RequestComposition.QUERY;
|
||||||
|
} else if (requestVModel.value.rest.length > 0) {
|
||||||
|
requestVModel.value.activeTab = RequestComposition.REST;
|
||||||
|
} else if (requestVModel.value.headers.length > 0) {
|
||||||
|
requestVModel.value.activeTab = RequestComposition.HEADER;
|
||||||
|
} else {
|
||||||
|
requestVModel.value.activeTab = RequestComposition.BODY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function initQuoteApiDetail() {
|
async function initQuoteApiDetail() {
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
@ -1287,6 +1301,7 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
requestVModel.value.activeTab = contentTabList.value[0].value;
|
requestVModel.value.activeTab = contentTabList.value[0].value;
|
||||||
|
setDefaultActiveTab();
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
isSwitchingContent.value = false;
|
isSwitchingContent.value = false;
|
||||||
});
|
});
|
||||||
|
|
|
@ -28,17 +28,15 @@
|
||||||
@press-enter="updateStepName"
|
@press-enter="updateStepName"
|
||||||
@blur="updateStepName"
|
@blur="updateStepName"
|
||||||
/>
|
/>
|
||||||
<div v-show="!isShowEditStepNameInput" class="flex flex-1 items-center justify-between">
|
<div v-show="!isShowEditStepNameInput" class="flex flex-1 items-center justify-between overflow-hidden">
|
||||||
<div class="flex items-center gap-[8px]">
|
<div class="flex flex-1 items-center gap-[8px] overflow-hidden">
|
||||||
<a-tooltip :content="requestVModel.stepName || activeStep?.name">
|
<a-tooltip :content="requestVModel.stepName || activeStep?.name">
|
||||||
<div class="one-line-text max-w-[300px]">
|
<div class="one-line-text"> {{ requestVModel.stepName || characterLimit(activeStep?.name) }}</div>
|
||||||
{{ requestVModel.stepName || characterLimit(activeStep?.name) }}</div
|
|
||||||
>
|
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<MsIcon
|
<MsIcon
|
||||||
v-if="!activeStep || !activeStep.isQuoteScenarioStep"
|
v-if="!activeStep || !activeStep.isQuoteScenarioStep"
|
||||||
type="icon-icon_edit_outlined"
|
type="icon-icon_edit_outlined"
|
||||||
class="cursor-pointer hover:text-[rgb(var(--primary-5))]"
|
class="min-w-[16px] cursor-pointer hover:text-[rgb(var(--primary-5))]"
|
||||||
@click="showEditScriptNameInput"
|
@click="showEditScriptNameInput"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1020,6 +1018,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setDefaultActiveTab() {
|
||||||
|
if (requestVModel.value.body.bodyType !== RequestBodyFormat.NONE) {
|
||||||
|
requestVModel.value.activeTab = RequestComposition.BODY;
|
||||||
|
} else if (requestVModel.value.query.length > 0) {
|
||||||
|
requestVModel.value.activeTab = RequestComposition.QUERY;
|
||||||
|
} else if (requestVModel.value.rest.length > 0) {
|
||||||
|
requestVModel.value.activeTab = RequestComposition.REST;
|
||||||
|
} else if (requestVModel.value.headers.length > 0) {
|
||||||
|
requestVModel.value.activeTab = RequestComposition.HEADER;
|
||||||
|
} else {
|
||||||
|
requestVModel.value.activeTab = RequestComposition.BODY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 替换步骤
|
* 替换步骤
|
||||||
* @param newStep 替换的新步骤
|
* @param newStep 替换的新步骤
|
||||||
|
@ -1063,6 +1075,7 @@
|
||||||
await initQuoteCaseDetail();
|
await initQuoteCaseDetail();
|
||||||
}
|
}
|
||||||
handleActiveDebugProtocolChange(requestVModel.value.protocol);
|
handleActiveDebugProtocolChange(requestVModel.value.protocol);
|
||||||
|
setDefaultActiveTab();
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
isSwitchingContent.value = false;
|
isSwitchingContent.value = false;
|
||||||
});
|
});
|
||||||
|
|
|
@ -30,24 +30,25 @@
|
||||||
<pre class="response-header-pre">{{ currentResponse?.console }}</pre>
|
<pre class="response-header-pre">{{ currentResponse?.console }}</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<responseResult
|
<div v-else class="response-result">
|
||||||
v-else
|
<responseResult
|
||||||
:active-tab="ResponseComposition.BODY"
|
:active-tab="ResponseComposition.BODY"
|
||||||
:request-result="currentResponse"
|
:request-result="currentResponse"
|
||||||
:console="currentResponse?.console"
|
:console="currentResponse?.console"
|
||||||
:show-empty="false"
|
:show-empty="false"
|
||||||
:is-edit="false"
|
:is-edit="false"
|
||||||
is-definition
|
is-definition
|
||||||
>
|
>
|
||||||
<template #titleLeft>
|
<template #titleLeft>
|
||||||
<div class="flex items-center text-[14px]">
|
<div class="flex items-center text-[14px]">
|
||||||
<div class="font-medium text-[var(--color-text-1)]">{{ t('apiScenario.response') }}</div>
|
<div class="font-medium text-[var(--color-text-1)]">{{ t('apiScenario.response') }}</div>
|
||||||
<a-tooltip :content="props.step.name">
|
<a-tooltip :content="props.step.name">
|
||||||
<div class="one-line-text">({{ props.step.name }})</div>
|
<div class="one-line-text">({{ props.step.name }})</div>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</responseResult>
|
</responseResult>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -129,17 +130,21 @@
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
border-radius: var(--border-radius-small);
|
border-radius: var(--border-radius-small);
|
||||||
}
|
}
|
||||||
.response {
|
.response-result {
|
||||||
.response-head {
|
@apply h-full overflow-auto bg-white;
|
||||||
background-color: var(--color-text-n9);
|
.ms-scroll-bar();
|
||||||
}
|
.response {
|
||||||
|
.response-head {
|
||||||
|
background-color: var(--color-text-n9);
|
||||||
|
}
|
||||||
|
|
||||||
border: 1px solid var(--color-text-n8);
|
border: 1px solid var(--color-text-n8);
|
||||||
border-radius: var(--border-radius-small);
|
border-radius: var(--border-radius-small);
|
||||||
.arco-spin {
|
.arco-spin {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
.response-container {
|
.response-container {
|
||||||
padding: 0 16px 14px;
|
padding: 0 16px 14px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="h-full">
|
||||||
<div class="mb-[8px] flex items-center gap-[8px]">
|
<div class="mb-[8px] flex items-center gap-[8px]">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:model-value="moduleKeyword"
|
v-model:model-value="moduleKeyword"
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
</div>
|
</div>
|
||||||
<a-divider class="my-[8px]" />
|
<a-divider class="my-[8px]" />
|
||||||
|
|
||||||
<a-spin class="w-full" :style="{ height: `calc(100vh - 300px)` }" :loading="loading">
|
<a-spin class="w-full" :style="{ height: `calc(100vh - 248px)` }" :loading="loading">
|
||||||
<MsTree
|
<MsTree
|
||||||
v-model:focus-node-key="focusNodeKey"
|
v-model:focus-node-key="focusNodeKey"
|
||||||
v-model:selected-keys="selectedKeys"
|
v-model:selected-keys="selectedKeys"
|
||||||
|
@ -178,16 +178,8 @@
|
||||||
const { openModal } = useModal();
|
const { openModal } = useModal();
|
||||||
|
|
||||||
const virtualListProps = computed(() => {
|
const virtualListProps = computed(() => {
|
||||||
if (props.readOnly) {
|
|
||||||
return {
|
|
||||||
height: 'calc(60vh - 325px)',
|
|
||||||
threshold: 200,
|
|
||||||
fixedSize: true,
|
|
||||||
buffer: 15, // 缓冲区默认 10 的时候,虚拟滚动的底部 padding 计算有问题
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
height: 'calc(100vh - 300px)',
|
height: '100%',
|
||||||
threshold: 200,
|
threshold: 200,
|
||||||
fixedSize: true,
|
fixedSize: true,
|
||||||
buffer: 15, // 缓冲区默认 10 的时候,虚拟滚动的底部 padding 计算有问题
|
buffer: 15, // 缓冲区默认 10 的时候,虚拟滚动的底部 padding 计算有问题
|
||||||
|
|
|
@ -120,7 +120,7 @@
|
||||||
</div>
|
</div>
|
||||||
<a-tooltip v-else :content="step.name">
|
<a-tooltip v-else :content="step.name">
|
||||||
<div class="step-name-container">
|
<div class="step-name-container">
|
||||||
<div class="one-line-text mr-[4px] max-w-[350px] font-medium text-[var(--color-text-1)]">
|
<div class="step-name-text one-line-text font-medium">
|
||||||
{{ step.name }}
|
{{ step.name }}
|
||||||
</div>
|
</div>
|
||||||
<MsIcon
|
<MsIcon
|
||||||
|
@ -155,11 +155,7 @@
|
||||||
</div>
|
</div>
|
||||||
<a-tooltip :content="step.name" :disabled="!step.name">
|
<a-tooltip :content="step.name" :disabled="!step.name">
|
||||||
<div class="step-name-container">
|
<div class="step-name-container">
|
||||||
<div
|
<div class="step-name-text one-line-text font-normal">
|
||||||
:class="`one-line-text mr-[4px] ${
|
|
||||||
step.stepType === ScenarioStepType.ONCE_ONLY_CONTROLLER ? 'max-w-[750px]' : 'max-w-[150px]'
|
|
||||||
} font-normal text-[var(--color-text-1)]`"
|
|
||||||
>
|
|
||||||
{{ step.name || t('apiScenario.pleaseInputStepDesc') }}
|
{{ step.name || t('apiScenario.pleaseInputStepDesc') }}
|
||||||
</div>
|
</div>
|
||||||
<MsIcon
|
<MsIcon
|
||||||
|
@ -1376,6 +1372,9 @@
|
||||||
background-color: var(--color-text-n9) !important;
|
background-color: var(--color-text-n9) !important;
|
||||||
.arco-tree-node-title {
|
.arco-tree-node-title {
|
||||||
background-color: var(--color-text-n9) !important;
|
background-color: var(--color-text-n9) !important;
|
||||||
|
.step-name-text {
|
||||||
|
max-width: calc(100% - 244px) !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.arco-tree-node-title {
|
.arco-tree-node-title {
|
||||||
|
@ -1391,7 +1390,7 @@
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
.step-name-container {
|
.step-name-container {
|
||||||
@apply flex items-center;
|
@apply flex flex-1 items-center overflow-hidden;
|
||||||
|
|
||||||
margin-right: 16px;
|
margin-right: 16px;
|
||||||
&:hover {
|
&:hover {
|
||||||
|
@ -1399,6 +1398,11 @@
|
||||||
@apply visible;
|
@apply visible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.step-name-text {
|
||||||
|
margin-right: 4px;
|
||||||
|
max-width: calc(100% - 170px);
|
||||||
|
color: var(--color-text-1);
|
||||||
|
}
|
||||||
.edit-script-name-icon {
|
.edit-script-name-icon {
|
||||||
@apply invisible cursor-pointer;
|
@apply invisible cursor-pointer;
|
||||||
|
|
||||||
|
@ -1431,6 +1435,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
:deep(.step-tree-node-title) {
|
||||||
|
@apply w-full;
|
||||||
|
}
|
||||||
:deep(.step-tree-node-focus) {
|
:deep(.step-tree-node-focus) {
|
||||||
background-color: var(--color-text-n9) !important;
|
background-color: var(--color-text-n9) !important;
|
||||||
.arco-tree-node-title {
|
.arco-tree-node-title {
|
||||||
|
|
|
@ -1,101 +1,97 @@
|
||||||
<template>
|
<template>
|
||||||
<MsCard no-content-padding simple>
|
<MsCard no-content-padding simple>
|
||||||
<div class="flex items-center justify-between p-[8px_16px_8px_16px]">
|
<MsSplitBox :size="300" :max="0.5">
|
||||||
<MsEditableTab
|
<template #first>
|
||||||
v-model:active-tab="activeScenarioTab"
|
<div class="flex h-full flex-col">
|
||||||
v-model:tabs="scenarioTabs"
|
<div class="flex-1 p-[16px]">
|
||||||
v-permission="['PROJECT_API_SCENARIO:READ+ADD']"
|
<scenarioModuleTree
|
||||||
class="flex-1 overflow-hidden"
|
ref="scenarioModuleTreeRef"
|
||||||
@add="() => newTab()"
|
:is-show-scenario="isShowScenario"
|
||||||
>
|
@count-recycle-scenario="selectRecycleCount"
|
||||||
<template #label="{ tab }">
|
@folder-node-select="handleNodeSelect"
|
||||||
<a-tooltip :content="tab.name || tab.label" :mouse-enter-delay="500">
|
@init="handleModuleInit"
|
||||||
<div class="one-line-text max-w-[144px]">
|
@new-scenario="() => newTab()"
|
||||||
{{ tab.name || tab.label }}
|
></scenarioModuleTree>
|
||||||
|
</div>
|
||||||
|
<a-divider margin="0" />
|
||||||
|
<div class="case">
|
||||||
|
<div class="flex items-center px-[20px]" :class="getActiveClass('recycle')" @click="redirectRecycle()">
|
||||||
|
<MsIcon type="icon-icon_delete-trash_outlined" class="folder-icon" />
|
||||||
|
<div class="folder-name mx-[4px]">{{ t('apiScenario.tree.recycleBin') }}</div>
|
||||||
|
<div class="folder-count">({{ recycleModulesCount || 0 }})</div>
|
||||||
</div>
|
</div>
|
||||||
</a-tooltip>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
</MsEditableTab>
|
</template>
|
||||||
<div v-show="activeScenarioTab.id !== 'all'" class="flex items-center gap-[8px]">
|
<template #second>
|
||||||
<MsEnvironmentSelect :env="activeScenarioTab.environmentId" />
|
<div class="flex items-center justify-between p-[8px_16px_8px_16px]">
|
||||||
<executeButton
|
<MsEditableTab
|
||||||
ref="executeButtonRef"
|
v-model:active-tab="activeScenarioTab"
|
||||||
v-permission="['PROJECT_API_SCENARIO:READ+EXECUTE']"
|
v-model:tabs="scenarioTabs"
|
||||||
:execute-loading="activeScenarioTab.executeLoading"
|
v-permission="['PROJECT_API_SCENARIO:READ+ADD']"
|
||||||
@execute="(type) => handleExecute(type)"
|
class="flex-1 overflow-hidden"
|
||||||
@stop-debug="handleStopExecute"
|
@add="() => newTab()"
|
||||||
/>
|
>
|
||||||
<a-button
|
<template #label="{ tab }">
|
||||||
v-if="
|
<a-tooltip :content="tab.name || tab.label" :mouse-enter-delay="500">
|
||||||
activeScenarioTab.isNew
|
<div class="one-line-text max-w-[144px]">
|
||||||
? hasAnyPermission(['PROJECT_API_SCENARIO:READ+ADD'])
|
{{ tab.name || tab.label }}
|
||||||
: hasAnyPermission(['PROJECT_API_SCENARIO:READ+UPDATE'])
|
|
||||||
"
|
|
||||||
type="primary"
|
|
||||||
:loading="saveLoading"
|
|
||||||
@click="saveScenario"
|
|
||||||
>
|
|
||||||
{{ t('common.save') }}
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<a-divider class="!my-0" />
|
|
||||||
<div v-if="activeScenarioTab.id === 'all'" class="pageWrap">
|
|
||||||
<MsSplitBox :size="300" :max="0.5">
|
|
||||||
<template #first>
|
|
||||||
<div class="flex h-full flex-col">
|
|
||||||
<div class="p-[16px]">
|
|
||||||
<scenarioModuleTree
|
|
||||||
ref="scenarioModuleTreeRef"
|
|
||||||
:is-show-scenario="isShowScenario"
|
|
||||||
@count-recycle-scenario="selectRecycleCount"
|
|
||||||
@folder-node-select="handleNodeSelect"
|
|
||||||
@init="handleModuleInit"
|
|
||||||
@new-scenario="() => newTab()"
|
|
||||||
></scenarioModuleTree>
|
|
||||||
</div>
|
|
||||||
<div class="flex-1">
|
|
||||||
<a-divider margin="0" />
|
|
||||||
<div class="case">
|
|
||||||
<div class="flex items-center px-[20px]" :class="getActiveClass('recycle')" @click="redirectRecycle()">
|
|
||||||
<MsIcon type="icon-icon_delete-trash_outlined" class="folder-icon" />
|
|
||||||
<div class="folder-name mx-[4px]">{{ t('apiScenario.tree.recycleBin') }}</div>
|
|
||||||
<div class="folder-count">({{ recycleModulesCount || 0 }})</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</a-tooltip>
|
||||||
</div>
|
</template>
|
||||||
</div>
|
</MsEditableTab>
|
||||||
</template>
|
<div v-show="activeScenarioTab.id !== 'all'" class="flex items-center gap-[8px]">
|
||||||
<template #second>
|
<MsEnvironmentSelect :env="activeScenarioTab.environmentId" />
|
||||||
<div class="overflow-x-hidden">
|
<executeButton
|
||||||
<ScenarioTable
|
ref="executeButtonRef"
|
||||||
ref="apiTableRef"
|
v-permission="['PROJECT_API_SCENARIO:READ+EXECUTE']"
|
||||||
:active-module="activeModule"
|
:execute-loading="activeScenarioTab.executeLoading"
|
||||||
:offspring-ids="offspringIds"
|
@execute="(type) => handleExecute(type)"
|
||||||
@refresh-module-tree="refreshTree"
|
@stop-debug="handleStopExecute"
|
||||||
@open-scenario="openScenarioTab"
|
|
||||||
@create-scenario="() => newTab()"
|
|
||||||
/>
|
/>
|
||||||
|
<a-button
|
||||||
|
v-if="
|
||||||
|
activeScenarioTab.isNew
|
||||||
|
? hasAnyPermission(['PROJECT_API_SCENARIO:READ+ADD'])
|
||||||
|
: hasAnyPermission(['PROJECT_API_SCENARIO:READ+UPDATE'])
|
||||||
|
"
|
||||||
|
type="primary"
|
||||||
|
:loading="saveLoading"
|
||||||
|
@click="saveScenario"
|
||||||
|
>
|
||||||
|
{{ t('common.save') }}
|
||||||
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
</MsSplitBox>
|
<a-divider class="!my-0" />
|
||||||
</div>
|
<div v-if="activeScenarioTab.id === 'all'" class="pageWrap overflow-x-hidden">
|
||||||
<div v-else-if="activeScenarioTab.isNew" class="pageWrap">
|
<ScenarioTable
|
||||||
<create
|
ref="apiTableRef"
|
||||||
ref="createRef"
|
:active-module="activeModule"
|
||||||
v-model:scenario="activeScenarioTab"
|
:offspring-ids="offspringIds"
|
||||||
:module-tree="moduleTree"
|
@refresh-module-tree="refreshTree"
|
||||||
@batch-debug="realExecute($event, false)"
|
@open-scenario="openScenarioTab"
|
||||||
></create>
|
@create-scenario="() => newTab()"
|
||||||
</div>
|
/>
|
||||||
<div v-else class="pageWrap">
|
</div>
|
||||||
<detail
|
<div v-else-if="activeScenarioTab.isNew" class="pageWrap">
|
||||||
ref="detailRef"
|
<create
|
||||||
v-model:scenario="activeScenarioTab"
|
ref="createRef"
|
||||||
:module-tree="moduleTree"
|
v-model:scenario="activeScenarioTab"
|
||||||
@batch-debug="realExecute($event, false)"
|
:module-tree="moduleTree"
|
||||||
></detail>
|
@batch-debug="realExecute($event, false)"
|
||||||
</div>
|
></create>
|
||||||
|
</div>
|
||||||
|
<div v-else class="pageWrap">
|
||||||
|
<detail
|
||||||
|
ref="detailRef"
|
||||||
|
v-model:scenario="activeScenarioTab"
|
||||||
|
:module-tree="moduleTree"
|
||||||
|
@batch-debug="realExecute($event, false)"
|
||||||
|
></detail>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</MsSplitBox>
|
||||||
</MsCard>
|
</MsCard>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -707,43 +703,43 @@
|
||||||
height: calc(100% - 50px);
|
height: calc(100% - 50px);
|
||||||
border-radius: var(--border-radius-large);
|
border-radius: var(--border-radius-large);
|
||||||
@apply bg-white;
|
@apply bg-white;
|
||||||
.case {
|
}
|
||||||
padding: 8px 4px;
|
.case {
|
||||||
border-radius: var(--border-radius-small);
|
padding: 8px 4px;
|
||||||
@apply flex cursor-pointer items-center justify-between;
|
border-radius: var(--border-radius-small);
|
||||||
&:hover {
|
@apply flex cursor-pointer items-center justify-between;
|
||||||
background-color: rgb(var(--primary-1));
|
&:hover {
|
||||||
}
|
background-color: rgb(var(--primary-1));
|
||||||
.folder-icon {
|
}
|
||||||
margin-right: 4px;
|
.folder-icon {
|
||||||
color: var(--color-text-4);
|
margin-right: 4px;
|
||||||
}
|
color: var(--color-text-4);
|
||||||
.folder-name {
|
}
|
||||||
color: var(--color-text-1);
|
.folder-name {
|
||||||
}
|
color: var(--color-text-1);
|
||||||
|
}
|
||||||
|
.folder-count {
|
||||||
|
margin-left: 4px;
|
||||||
|
color: var(--color-text-4);
|
||||||
|
}
|
||||||
|
.case-active {
|
||||||
|
.folder-icon,
|
||||||
|
.folder-name,
|
||||||
.folder-count {
|
.folder-count {
|
||||||
margin-left: 4px;
|
color: rgb(var(--primary-5));
|
||||||
color: var(--color-text-4);
|
|
||||||
}
|
}
|
||||||
.case-active {
|
}
|
||||||
.folder-icon,
|
.back {
|
||||||
.folder-name,
|
margin-right: 8px;
|
||||||
.folder-count {
|
width: 20px;
|
||||||
color: rgb(var(--primary-5));
|
height: 20px;
|
||||||
}
|
border: 1px solid #ffffff;
|
||||||
}
|
background: linear-gradient(90deg, rgb(var(--primary-9)) 3.36%, #ffffff 100%);
|
||||||
.back {
|
box-shadow: 0 0 7px rgb(15 0 78 / 9%);
|
||||||
margin-right: 8px;
|
.arco-icon {
|
||||||
width: 20px;
|
color: rgb(var(--primary-5));
|
||||||
height: 20px;
|
|
||||||
border: 1px solid #ffffff;
|
|
||||||
background: linear-gradient(90deg, rgb(var(--primary-9)) 3.36%, #ffffff 100%);
|
|
||||||
box-shadow: 0 0 7px rgb(15 0 78 / 9%);
|
|
||||||
.arco-icon {
|
|
||||||
color: rgb(var(--primary-5));
|
|
||||||
}
|
|
||||||
@apply flex cursor-pointer items-center rounded-full;
|
|
||||||
}
|
}
|
||||||
|
@apply flex cursor-pointer items-center rounded-full;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.recycle {
|
.recycle {
|
||||||
|
|
|
@ -1,48 +1,46 @@
|
||||||
<template>
|
<template>
|
||||||
<MsCard has-breadcrumb no-content-padding simple>
|
<MsCard has-breadcrumb no-content-padding simple>
|
||||||
<div class="p-[24px_24px_8px_24px]">
|
<MsSplitBox :size="300" :max="0.5">
|
||||||
<MsEditableTab
|
<template #first>
|
||||||
v-model:active-tab="activeApiTab"
|
<div class="h-full p-[16px]">
|
||||||
v-model:tabs="apiTabs"
|
<recycleTree
|
||||||
class="flex-1 overflow-hidden"
|
ref="recycleTreeRef"
|
||||||
:show-add="false"
|
:is-show-scenario="isShowScenario"
|
||||||
:readonly="true"
|
@folder-node-select="handleNodeSelect"
|
||||||
@add="newTab"
|
@init="handleModuleInit"
|
||||||
>
|
></recycleTree>
|
||||||
<template #label="{ tab }">
|
</div>
|
||||||
<a-tooltip :content="tab.label" :mouse-enter-delay="500">
|
</template>
|
||||||
<div class="one-line-text max-w-[144px]">
|
<template #second>
|
||||||
{{ tab.label }}
|
<div class="p-[24px_24px_8px_24px]">
|
||||||
</div>
|
<MsEditableTab
|
||||||
</a-tooltip>
|
v-model:active-tab="activeApiTab"
|
||||||
</template>
|
v-model:tabs="apiTabs"
|
||||||
</MsEditableTab>
|
class="flex-1 overflow-hidden"
|
||||||
</div>
|
:show-add="false"
|
||||||
<a-divider class="!my-0" />
|
:readonly="true"
|
||||||
<div v-if="activeApiTab.id === 'all'" class="pageWrap">
|
@add="newTab"
|
||||||
<MsSplitBox :size="300" :max="0.5">
|
>
|
||||||
<template #first>
|
<template #label="{ tab }">
|
||||||
<div class="flex h-full flex-col">
|
<a-tooltip :content="tab.label" :mouse-enter-delay="500">
|
||||||
<div class="p-[16px]">
|
<div class="one-line-text max-w-[144px]">
|
||||||
<recycleTree
|
{{ tab.label }}
|
||||||
ref="recycleTreeRef"
|
</div>
|
||||||
:is-show-scenario="isShowScenario"
|
</a-tooltip>
|
||||||
@folder-node-select="handleNodeSelect"
|
</template>
|
||||||
@init="handleModuleInit"
|
</MsEditableTab>
|
||||||
></recycleTree>
|
</div>
|
||||||
</div>
|
<a-divider class="!my-0" />
|
||||||
</div>
|
<div v-if="activeApiTab.id === 'all'" class="pageWrap">
|
||||||
</template>
|
|
||||||
<template #second>
|
|
||||||
<RecycleTable
|
<RecycleTable
|
||||||
ref="apiTableRef"
|
ref="apiTableRef"
|
||||||
:active-module="activeModule"
|
:active-module="activeModule"
|
||||||
:offspring-ids="offspringIds"
|
:offspring-ids="offspringIds"
|
||||||
@refresh-module-tree="refreshTree"
|
@refresh-module-tree="refreshTree"
|
||||||
/>
|
/>
|
||||||
</template>
|
</div>
|
||||||
</MsSplitBox>
|
</template>
|
||||||
</div>
|
</MsSplitBox>
|
||||||
<!-- <detail v-else v-model:scenario="activeApiTab"></detail> -->
|
<!-- <detail v-else v-model:scenario="activeApiTab"></detail> -->
|
||||||
</MsCard>
|
</MsCard>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="h-full">
|
||||||
<div class="folder" @click="setActiveFolder('all')">
|
<div class="folder" @click="setActiveFolder('all')">
|
||||||
<div :class="allFolderClass">
|
<div :class="allFolderClass">
|
||||||
<MsIcon type="icon-icon_folder_filled1" class="folder-icon" />
|
<MsIcon type="icon-icon_folder_filled1" class="folder-icon" />
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
allow-clear
|
allow-clear
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<a-spin class="w-full" :loading="loading">
|
<a-spin class="w-full" :style="{ height: `calc(100vh - 248px)` }" :loading="loading">
|
||||||
<MsTree
|
<MsTree
|
||||||
v-model:focus-node-key="focusNodeKey"
|
v-model:focus-node-key="focusNodeKey"
|
||||||
v-model:selected-keys="selectedKeys"
|
v-model:selected-keys="selectedKeys"
|
||||||
|
@ -102,7 +102,7 @@
|
||||||
|
|
||||||
const virtualListProps = computed(() => {
|
const virtualListProps = computed(() => {
|
||||||
return {
|
return {
|
||||||
height: 'calc(100vh - 343px)',
|
height: '100%',
|
||||||
threshold: 200,
|
threshold: 200,
|
||||||
fixedSize: true,
|
fixedSize: true,
|
||||||
buffer: 15, // 缓冲区默认 10 的时候,虚拟滚动的底部 padding 计算有问题
|
buffer: 15, // 缓冲区默认 10 的时候,虚拟滚动的底部 padding 计算有问题
|
||||||
|
|
|
@ -210,7 +210,6 @@
|
||||||
<div class="mt-[16px] h-[calc(100%-32px)] border-t border-[var(--color-text-n8)]">
|
<div class="mt-[16px] h-[calc(100%-32px)] border-t border-[var(--color-text-n8)]">
|
||||||
<!-- 脑图开始 -->
|
<!-- 脑图开始 -->
|
||||||
<MsFeatureCaseMinder
|
<MsFeatureCaseMinder
|
||||||
minder-type="FeatureCase"
|
|
||||||
:module-id="props.activeFolder"
|
:module-id="props.activeFolder"
|
||||||
:modules-count="props.modulesCount"
|
:modules-count="props.modulesCount"
|
||||||
:module-name="props.moduleName"
|
:module-name="props.moduleName"
|
||||||
|
|
|
@ -102,7 +102,7 @@
|
||||||
</MsCard>
|
</MsCard>
|
||||||
<!-- special-height的174: 上面卡片高度158 + mt的16 -->
|
<!-- special-height的174: 上面卡片高度158 + mt的16 -->
|
||||||
<MsCard class="mt-[16px]" :special-height="174" simple has-breadcrumb no-content-padding>
|
<MsCard class="mt-[16px]" :special-height="174" simple has-breadcrumb no-content-padding>
|
||||||
<Plan v-if="activeTab === 'plan'" :plan-id="planId" />
|
<Plan v-if="activeTab === 'plan'" :plan-id="planId" @refresh="initDetail" />
|
||||||
<FeatureCase
|
<FeatureCase
|
||||||
v-if="activeTab === 'featureCase'"
|
v-if="activeTab === 'featureCase'"
|
||||||
ref="featureCaseRef"
|
ref="featureCaseRef"
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="flex h-full flex-col">
|
<div class="flex h-full flex-col p-[16px]">
|
||||||
<MsNotRemind tip="testPlan.planTip" class="p-[16px]" type="info" visited-key="testPlanTip" />
|
<MsNotRemind tip="testPlan.planTip" class="mb-[16px]" type="info" visited-key="testPlanTip" />
|
||||||
<div class="flex-1 overflow-hidden p-[16px]">
|
<div class="flex-1 overflow-hidden">
|
||||||
<MsTestPlanMinder :plan-id="props.planId" />
|
<MsTestPlanMinder :plan-id="props.planId" @save="emit('refresh')" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -14,6 +14,9 @@
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
planId: string;
|
planId: string;
|
||||||
}>();
|
}>();
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'refresh'): void;
|
||||||
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped></style>
|
||||||
|
|
Loading…
Reference in New Issue