fix(全局): 部分 bug 修复
This commit is contained in:
parent
e4b1c29dc8
commit
413c7fc7b3
|
@ -188,8 +188,8 @@ export function saveCaseMinder(data: FeatureCaseMinderUpdateParams) {
|
|||
}
|
||||
|
||||
// 获取脑图
|
||||
export function getCaseMinder(data: { projectId: string; moduleId: string }) {
|
||||
return MSR.post<MinderJsonNode[]>({ url: `${GetCaseMinderUrl}`, data });
|
||||
export function getCaseMinder(data: { projectId: string; moduleId: string; current: number }) {
|
||||
return MSR.post<CommonList<MinderJsonNode>>({ url: `${GetCaseMinderUrl}`, data });
|
||||
}
|
||||
|
||||
// 获取脑图模块树(包含文本节点)
|
||||
|
|
|
@ -370,6 +370,7 @@
|
|||
.ms-scroll-bar();
|
||||
|
||||
padding-right: 16px;
|
||||
min-height: 30px;
|
||||
}
|
||||
.arco-textarea-wrapper {
|
||||
resize: vertical !important;
|
||||
|
|
|
@ -138,7 +138,6 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineModel } from 'vue';
|
||||
import { useVModel } from '@vueuse/core';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { VueDraggable } from 'vue-draggable-plus';
|
||||
|
|
|
@ -7,14 +7,14 @@ export default {
|
|||
'ms.case.associate.version': '版本',
|
||||
'ms.case.associate.versionPlaceholder': '默认最新版本',
|
||||
'ms.case.associate.tags': '标签',
|
||||
'ms.case.associate.searchPlaceholder': '通过 ID 或名称搜索',
|
||||
'ms.case.associate.searchPlaceholder': '通过 ID/名称搜索',
|
||||
'ms.case.associate.associateSuccess': '关联成功',
|
||||
'ms.case.associate.functionalCase': '功能用例',
|
||||
'ms.case.associate.apiCase': '接口用例',
|
||||
'ms.case.associate.apiScenarioCase': '接口场景用例',
|
||||
'ms.case.associate.UIScenario': 'UI场景用例',
|
||||
'ms.case.associate.performanceCase': '性能用例',
|
||||
'ms.case.associate.testSet': '测试集',
|
||||
'ms.case.associate.testSet': '测试点',
|
||||
'ms.case.associate.addAssociatedCase': '添加已关联用例',
|
||||
'ms.case.associate.automaticallyAddApiCase': '自动添加已关联的接口用例',
|
||||
'ms.case.associate.project': '项目',
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
>
|
||||
<div
|
||||
v-for="(element, index) in form.list"
|
||||
:key="`${element.filed}${index}`"
|
||||
:key="`${element.field}${index}`"
|
||||
class="draggableElement gap-[8px] py-[6px] pr-[8px]"
|
||||
:class="[props.isShowDrag ? 'cursor-move' : '']"
|
||||
>
|
||||
|
@ -25,14 +25,14 @@
|
|||
/></div>
|
||||
<a-form-item
|
||||
v-for="model of props.models"
|
||||
:key="`${model.filed}${index}`"
|
||||
:field="`list[${index}].${model.filed}`"
|
||||
:key="`${model.field}${index}`"
|
||||
:field="`list[${index}].${model.field}`"
|
||||
:class="index > 0 ? 'hidden-item' : 'mb-0 flex-1'"
|
||||
:rules="
|
||||
model.rules?.map((e) => {
|
||||
if (e.notRepeat === true) {
|
||||
return {
|
||||
validator: (val, callback) => fieldNotRepeat(val, callback, index, model.filed, e.message),
|
||||
validator: (val, callback) => fieldNotRepeat(val, callback, index, model.field, e.message),
|
||||
};
|
||||
}
|
||||
return e;
|
||||
|
@ -59,17 +59,30 @@
|
|||
</template>
|
||||
<a-input
|
||||
v-if="model.type === 'input'"
|
||||
v-model:model-value="element[model.filed]"
|
||||
v-model:model-value="element[model.field]"
|
||||
class="flex-1"
|
||||
:placeholder="t(model.placeholder || '')"
|
||||
:max-length="model.maxLength || 255"
|
||||
allow-clear
|
||||
@change="emit('change')"
|
||||
/>
|
||||
<MsQuickInput
|
||||
v-else-if="model.type === 'textarea'"
|
||||
v-model:model-value="element[model.field]"
|
||||
class="flex-1"
|
||||
type="textarea"
|
||||
@change="
|
||||
() => {
|
||||
formRef?.validateField(`list[${index}].${model.field}`);
|
||||
emit('change');
|
||||
}
|
||||
"
|
||||
>
|
||||
</MsQuickInput>
|
||||
<a-tooltip v-else-if="model.type === 'inputNumber'" position="tl" mini :disabled="!model.tooltip">
|
||||
<a-input-number
|
||||
v-if="model.type === 'inputNumber'"
|
||||
v-model:model-value="element[model.filed]"
|
||||
v-model:model-value="element[model.field]"
|
||||
class="flex-1"
|
||||
:placeholder="t(model.placeholder || '')"
|
||||
:min="model.min"
|
||||
|
@ -89,7 +102,7 @@
|
|||
</a-tooltip>
|
||||
<MsTagsInput
|
||||
v-else-if="model.type === 'tagInput'"
|
||||
v-model:model-value="element[model.filed]"
|
||||
v-model:model-value="element[model.field]"
|
||||
class="flex-1"
|
||||
:placeholder="t(model.placeholder || 'common.tagPlaceholder')"
|
||||
allow-clear
|
||||
|
@ -100,7 +113,7 @@
|
|||
/>
|
||||
<a-select
|
||||
v-else-if="model.type === 'select'"
|
||||
v-model="element[model.filed]"
|
||||
v-model="element[model.field]"
|
||||
class="flex-1"
|
||||
:placeholder="t(model.placeholder || '')"
|
||||
:options="model.options"
|
||||
|
@ -110,8 +123,8 @@
|
|||
<div v-else-if="model.type === 'multiple'" class="flex flex-row gap-[4px]">
|
||||
<a-form-item
|
||||
v-for="(child, childIndex) in model.children"
|
||||
:key="`${child.filed}${childIndex}${index}`"
|
||||
:field="`list[${index}].${child.filed}`"
|
||||
:key="`${child.field}${childIndex}${index}`"
|
||||
:field="`list[${index}].${child.field}`"
|
||||
:label="child.label ? t(child.label) : ''"
|
||||
asterisk-position="end"
|
||||
:hide-asterisk="child.hideAsterisk"
|
||||
|
@ -121,7 +134,7 @@
|
|||
>
|
||||
<a-input
|
||||
v-if="child.type === 'input'"
|
||||
v-model="element[child.filed]"
|
||||
v-model="element[child.field]"
|
||||
:class="child.className"
|
||||
:placeholder="t(child.placeholder || '')"
|
||||
:max-length="child.maxLength || 255"
|
||||
|
@ -130,13 +143,29 @@
|
|||
/>
|
||||
<a-select
|
||||
v-else-if="child.type === 'select'"
|
||||
v-model="element[child.filed]"
|
||||
v-model="element[child.field]"
|
||||
:class="child.className"
|
||||
:placeholder="t(child.placeholder || '')"
|
||||
:options="child.options"
|
||||
:field-names="child.filedNames"
|
||||
@change="emit('change')"
|
||||
/>
|
||||
<MsQuickInput
|
||||
v-else-if="child.type === 'textarea'"
|
||||
v-model="element[child.field]"
|
||||
type="textarea"
|
||||
:class="child.className"
|
||||
:placeholder="t(child.placeholder || '')"
|
||||
:max-length="child.maxLength || 255"
|
||||
:title="child.title"
|
||||
allow-clear
|
||||
@change="
|
||||
() => {
|
||||
formRef?.validateField(`list[${index}].${child.field}`);
|
||||
emit('change');
|
||||
}
|
||||
"
|
||||
/>
|
||||
</a-form-item>
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
@ -199,6 +228,7 @@
|
|||
import { VueDraggable } from 'vue-draggable-plus';
|
||||
|
||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||
import MsQuickInput from '@/components/business/ms-quick-input/index.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { scrollIntoView } from '@/utils/dom';
|
||||
|
@ -253,19 +283,19 @@
|
|||
} else {
|
||||
value = e.defaultValue;
|
||||
}
|
||||
formItem[e.filed] = value;
|
||||
formItem[e.field] = value;
|
||||
if (props.showEnable) {
|
||||
// 如果有开启关闭状态,将默认禁用
|
||||
formItem.enable = false;
|
||||
}
|
||||
// 默认填充表单项的子项
|
||||
e.children?.forEach((child) => {
|
||||
formItem[child.filed] = child.type === 'inputNumber' ? null : child.defaultValue;
|
||||
formItem[child.field] = child.type === 'inputNumber' ? null : child.defaultValue;
|
||||
});
|
||||
});
|
||||
form.value.list = [{ ...formItem }];
|
||||
if (props.defaultVals?.length) {
|
||||
// 取出defaultVals的表单 filed
|
||||
// 取出defaultVals的表单 field
|
||||
form.value.list = props.defaultVals.map((e) => e);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { FieldRule, SelectFieldNames, SelectOptionData, SelectOptionGroup } from '@arco-design/web-vue';
|
||||
|
||||
export type FormItemType = 'input' | 'select' | 'inputNumber' | 'tagInput' | 'multiple' | 'switch';
|
||||
export type FormItemType = 'input' | 'select' | 'inputNumber' | 'tagInput' | 'multiple' | 'switch' | 'textarea';
|
||||
export type FormMode = 'create' | 'edit';
|
||||
export type ValueType = 'Array' | 'string';
|
||||
// 自定义检验器,为了传入动态渲染的表单项下标
|
||||
|
@ -9,7 +9,7 @@ export interface CustomValidator {
|
|||
}
|
||||
|
||||
export interface FormItemModel {
|
||||
filed: string;
|
||||
field: string;
|
||||
type: FormItemType;
|
||||
rules?: (FieldRule & CustomValidator)[];
|
||||
label?: string;
|
||||
|
@ -26,4 +26,5 @@ export interface FormItemModel {
|
|||
defaultValue?: string | string[] | number | number[] | boolean; // 默认值
|
||||
hasRedStar?: boolean; // 是否有红星
|
||||
tooltip?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,6 @@ export default {
|
|||
'ms.case.associate.version': '版本',
|
||||
'ms.case.associate.versionPlaceholder': '默认最新版本',
|
||||
'ms.case.associate.tags': '标签',
|
||||
'ms.case.associate.searchPlaceholder': '通过 ID 或名称搜索',
|
||||
'ms.case.associate.searchPlaceholder': '通过 ID/名称搜索',
|
||||
'ms.case.associate.associateSuccess': '关联成功',
|
||||
};
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineModel, ref } from 'vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import MsAvatar from '@/components/pure/ms-avatar/index.vue';
|
||||
|
|
|
@ -41,8 +41,6 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineModel, ref } from 'vue';
|
||||
|
||||
import MsAvatar from '@/components/pure/ms-avatar/index.vue';
|
||||
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
|
||||
|
||||
|
|
|
@ -147,8 +147,6 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineModel, ref } from 'vue';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
|
||||
import { Language } from '@/components/pure/ms-code-editor/types';
|
||||
|
|
|
@ -353,6 +353,199 @@
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化模块节点下的用例节点
|
||||
* @param node 选中节点
|
||||
*/
|
||||
async function initNodeCases(node: MinderJsonNode) {
|
||||
try {
|
||||
const { data } = node;
|
||||
if (!data) return;
|
||||
loading.value = true;
|
||||
const { list, total } = await getCaseMinder({
|
||||
projectId: appStore.currentProjectId,
|
||||
moduleId: data.id,
|
||||
current: 1,
|
||||
});
|
||||
const fakeNode = node.children?.find((e) => e.data?.id === 'fakeNode'); // 移除占位的虚拟节点
|
||||
if (fakeNode) {
|
||||
window.minder.removeNode(fakeNode);
|
||||
}
|
||||
if ((!list || list.length === 0) && node.children?.length) {
|
||||
// 如果模块下没有用例且有别的模块节点,正常展开
|
||||
node.expand();
|
||||
window.minder.renderNodeBatch(node.children);
|
||||
node.layout();
|
||||
data.isLoaded = true;
|
||||
return;
|
||||
}
|
||||
// TODO:递归渲染存在的子节点
|
||||
let waitingRenderNodes: MinderJsonNode[] = [];
|
||||
list.forEach((e) => {
|
||||
// 用例节点
|
||||
const child = window.minder.createNode(
|
||||
{
|
||||
...e.data,
|
||||
expandState: 'collapse',
|
||||
isNew: false,
|
||||
},
|
||||
node
|
||||
);
|
||||
waitingRenderNodes.push(child);
|
||||
const grandChildren: MinderJsonNode[] = [];
|
||||
e.children?.forEach((item) => {
|
||||
// 前置/步骤/备注节点
|
||||
const grandChild = window.minder.createNode(
|
||||
{
|
||||
...item.data,
|
||||
expandState: 'collapse',
|
||||
isNew: false,
|
||||
},
|
||||
child
|
||||
);
|
||||
grandChildren.push(grandChild);
|
||||
const greatGrandChildren: MinderJsonNode[] = [];
|
||||
item.children?.forEach((subItem) => {
|
||||
// 预期结果节点
|
||||
const greatGrandChild = window.minder.createNode(
|
||||
{
|
||||
...subItem.data,
|
||||
expandState: 'collapse',
|
||||
isNew: false,
|
||||
},
|
||||
grandChild
|
||||
);
|
||||
greatGrandChildren.push(greatGrandChild);
|
||||
});
|
||||
window.minder.renderNodeBatch(greatGrandChildren);
|
||||
});
|
||||
window.minder.renderNodeBatch(grandChildren);
|
||||
});
|
||||
node.expand();
|
||||
// node.renderTree();
|
||||
if (node.children && node.children.length > 0) {
|
||||
waitingRenderNodes = waitingRenderNodes.concat(node.children);
|
||||
}
|
||||
if (total > list.length) {
|
||||
// 有更多用例
|
||||
const moreNode = window.minder.createNode(
|
||||
{
|
||||
id: `tmp-${data.id}`,
|
||||
text: '...',
|
||||
type: 'tmp',
|
||||
expandState: 'collapse',
|
||||
current: 1,
|
||||
},
|
||||
node
|
||||
);
|
||||
waitingRenderNodes.push(moreNode);
|
||||
}
|
||||
window.minder.renderNodeBatch(waitingRenderNodes);
|
||||
node.layout();
|
||||
data.isLoaded = true;
|
||||
// 加载完用例数据后,更新当前importJson数据
|
||||
replaceNodeInTree([importJson.value.root], node.data?.id || '', window.minder.exportNode(node), 'data', 'id');
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载模块下更多用例
|
||||
* @param node 模块节点
|
||||
* @param current 当前页码
|
||||
*/
|
||||
async function loadMoreCases(node: MinderJsonNode, current: number) {
|
||||
try {
|
||||
const { data } = node;
|
||||
if (!data) return;
|
||||
loading.value = true;
|
||||
const { list, total } = await getCaseMinder({
|
||||
projectId: appStore.currentProjectId,
|
||||
moduleId: data.id,
|
||||
current: current + 1,
|
||||
});
|
||||
const fakeNode = node.children?.find((e) => e.data?.id === `tmp-${data.id}`); // 移除占位的虚拟节点
|
||||
if (fakeNode) {
|
||||
window.minder.removeNode(fakeNode);
|
||||
}
|
||||
// TODO:递归渲染存在的子节点
|
||||
let waitingRenderNodes: MinderJsonNode[] = [];
|
||||
list.forEach((e) => {
|
||||
// 用例节点
|
||||
const child = window.minder.createNode(
|
||||
{
|
||||
...e.data,
|
||||
expandState: 'collapse',
|
||||
isNew: false,
|
||||
},
|
||||
node
|
||||
);
|
||||
waitingRenderNodes.push(child);
|
||||
const grandChildren: MinderJsonNode[] = [];
|
||||
e.children?.forEach((item) => {
|
||||
// 前置/步骤/备注节点
|
||||
const grandChild = window.minder.createNode(
|
||||
{
|
||||
...item.data,
|
||||
expandState: 'collapse',
|
||||
isNew: false,
|
||||
},
|
||||
child
|
||||
);
|
||||
grandChildren.push(grandChild);
|
||||
const greatGrandChildren: MinderJsonNode[] = [];
|
||||
item.children?.forEach((subItem) => {
|
||||
// 预期结果节点
|
||||
const greatGrandChild = window.minder.createNode(
|
||||
{
|
||||
...subItem.data,
|
||||
expandState: 'collapse',
|
||||
isNew: false,
|
||||
},
|
||||
grandChild
|
||||
);
|
||||
greatGrandChildren.push(greatGrandChild);
|
||||
});
|
||||
window.minder.renderNodeBatch(greatGrandChildren);
|
||||
});
|
||||
window.minder.renderNodeBatch(grandChildren);
|
||||
});
|
||||
node.expand();
|
||||
// node.renderTree();
|
||||
if (node.children && node.children.length > 0) {
|
||||
waitingRenderNodes = waitingRenderNodes.concat(node.children);
|
||||
}
|
||||
if (total > list.length * current) {
|
||||
// 有更多用例
|
||||
const moreNode = window.minder.createNode(
|
||||
{
|
||||
id: `tmp-${data.id}`,
|
||||
text: '...',
|
||||
type: 'tmp',
|
||||
expandState: 'collapse',
|
||||
current: current + 1,
|
||||
},
|
||||
node
|
||||
);
|
||||
waitingRenderNodes.push(moreNode);
|
||||
}
|
||||
window.minder.renderNodeBatch(waitingRenderNodes);
|
||||
node.layout();
|
||||
data.isLoaded = true;
|
||||
// 加载完用例数据后,更新当前importJson数据
|
||||
replaceNodeInTree([importJson.value.root], node.data?.id || '', window.minder.exportNode(node), 'data', 'id');
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
const showDetailMenu = ref(false);
|
||||
const canShowEnterNode = ref(false);
|
||||
/**
|
||||
|
@ -360,8 +553,14 @@
|
|||
* @param node 被激活/点击的节点
|
||||
*/
|
||||
async function handleNodeSelect(node: MinderJsonNode) {
|
||||
checkNodeCanShowMenu(node);
|
||||
const { data } = node;
|
||||
checkNodeCanShowMenu(node);
|
||||
if (data?.type === 'tmp' && node.parent?.data?.resource?.includes(moduleTag)) {
|
||||
// 点击更多节点,加载更多用例
|
||||
await loadMoreCases(node.parent, data.current);
|
||||
setPriorityView(true, 'P');
|
||||
return;
|
||||
}
|
||||
if (
|
||||
data?.resource?.includes(moduleTag) &&
|
||||
(node.children || []).length > 0 &&
|
||||
|
@ -381,84 +580,9 @@
|
|||
}
|
||||
} else if (data?.resource?.includes(moduleTag) && data.count > 0 && data.isLoaded !== true) {
|
||||
// 模块节点且有用例且未加载过用例数据
|
||||
try {
|
||||
loading.value = true;
|
||||
showDetailMenu.value = false;
|
||||
extraVisible.value = false;
|
||||
const res = await getCaseMinder({
|
||||
projectId: appStore.currentProjectId,
|
||||
moduleId: data.id,
|
||||
});
|
||||
const fakeNode = node.children?.find((e) => e.data?.id === 'fakeNode'); // 移除占位的虚拟节点
|
||||
if (fakeNode) {
|
||||
window.minder.removeNode(fakeNode);
|
||||
}
|
||||
if ((!res || res.length === 0) && node.children?.length) {
|
||||
// 如果模块下没有用例且有别的模块节点,正常展开
|
||||
node.expand();
|
||||
window.minder.renderNodeBatch(node.children);
|
||||
node.layout();
|
||||
data.isLoaded = true;
|
||||
return;
|
||||
}
|
||||
// TODO:递归渲染存在的子节点
|
||||
let waitingRenderNodes: MinderJsonNode[] = [];
|
||||
res.forEach((e) => {
|
||||
// 用例节点
|
||||
const child = window.minder.createNode(
|
||||
{
|
||||
...e.data,
|
||||
expandState: 'collapse',
|
||||
isNew: false,
|
||||
},
|
||||
node
|
||||
);
|
||||
waitingRenderNodes.push(child);
|
||||
const grandChildren: MinderJsonNode[] = [];
|
||||
e.children?.forEach((item) => {
|
||||
// 前置/步骤/备注节点
|
||||
const grandChild = window.minder.createNode(
|
||||
{
|
||||
...item.data,
|
||||
expandState: 'collapse',
|
||||
isNew: false,
|
||||
},
|
||||
child
|
||||
);
|
||||
grandChildren.push(grandChild);
|
||||
const greatGrandChildren: MinderJsonNode[] = [];
|
||||
item.children?.forEach((subItem) => {
|
||||
// 预期结果节点
|
||||
const greatGrandChild = window.minder.createNode(
|
||||
{
|
||||
...subItem.data,
|
||||
expandState: 'collapse',
|
||||
isNew: false,
|
||||
},
|
||||
grandChild
|
||||
);
|
||||
greatGrandChildren.push(greatGrandChild);
|
||||
});
|
||||
window.minder.renderNodeBatch(greatGrandChildren);
|
||||
});
|
||||
window.minder.renderNodeBatch(grandChildren);
|
||||
});
|
||||
node.expand();
|
||||
// node.renderTree();
|
||||
if (node.children && node.children.length > 0) {
|
||||
waitingRenderNodes = waitingRenderNodes.concat(node.children);
|
||||
}
|
||||
window.minder.renderNodeBatch(waitingRenderNodes);
|
||||
node.layout();
|
||||
data.isLoaded = true;
|
||||
// 加载完用例数据后,更新当前importJson数据
|
||||
replaceNodeInTree([importJson.value.root], node.data?.id || '', window.minder.exportNode(node), 'data', 'id');
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
await initNodeCases(node);
|
||||
showDetailMenu.value = false;
|
||||
extraVisible.value = false;
|
||||
} else {
|
||||
// 文本节点或已加载过用例数据的模块节点
|
||||
extraVisible.value = false;
|
||||
|
|
|
@ -35,6 +35,10 @@ export default function useMinderBaseApi({ hasEditPermission }: { hasEditPermiss
|
|||
function canShowFloatMenu() {
|
||||
if (window.minder) {
|
||||
const node: MinderJsonNode = window.minder.getSelectedNode();
|
||||
if (node.data?.type === 'tmp') {
|
||||
// 临时节点不展示浮动菜单
|
||||
return false;
|
||||
}
|
||||
if (!hasEditPermission) {
|
||||
if (node?.data?.resource?.includes(caseTag)) {
|
||||
// 没有编辑权限情况下,用例节点可展示浮动菜单(需要展示详情按钮)
|
||||
|
|
|
@ -379,6 +379,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
const inInsertingNode = ref(false);
|
||||
/**
|
||||
* 执行插入节点
|
||||
* @param command 插入命令
|
||||
|
@ -447,6 +448,7 @@
|
|||
};
|
||||
}
|
||||
if (child) {
|
||||
inInsertingNode.value = true;
|
||||
execInert(type, child);
|
||||
nextTick(() => {
|
||||
execInert('AppendChildNode', caseCountNodeData);
|
||||
|
@ -454,6 +456,9 @@
|
|||
// 功能用例测试点没有环境和资源池
|
||||
execInert('AppendSiblingNode', envNodeData);
|
||||
execInert('AppendSiblingNode', resourcePoolNodeData);
|
||||
setTimeout(() => {
|
||||
inInsertingNode.value = false;
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -669,7 +674,10 @@
|
|||
if (node.data?.level === 3 && node.data?.resource?.[0] === caseCountTag) {
|
||||
window.minder.toggleSelect(node);
|
||||
window.minder.selectById(node.parent?.data?.id);
|
||||
associateCase();
|
||||
if (!inInsertingNode.value && hasEditPermission && hasAnyPermission(['PROJECT_TEST_PLAN:READ+ASSOCIATION'])) {
|
||||
// 新增测试点时不自动弹出关联用例
|
||||
associateCase();
|
||||
}
|
||||
} else if (
|
||||
node.data?.level === 3 &&
|
||||
(node.data?.resource?.[0] === resourcePoolTag || node.data?.resource?.[0] === envTag)
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
<template>
|
||||
<a-popover position="tl" :disabled="!modelValue || modelValue.trim() === ''" class="ms-params-input-popover">
|
||||
<template #content>
|
||||
<div v-if="props.title" class="param-popover-title">
|
||||
{{ props.title }}
|
||||
</div>
|
||||
<div class="param-popover-value">
|
||||
{{ modelValue }}
|
||||
</div>
|
||||
</template>
|
||||
<a-input
|
||||
v-if="props.type === 'input'"
|
||||
ref="inputRef"
|
||||
v-model:model-value="modelValue"
|
||||
:class="props.class"
|
||||
:disabled="props.disabled"
|
||||
:size="props.size"
|
||||
:max-length="props.maxLength"
|
||||
:placeholder="props.placeholder"
|
||||
:trigger-props="{ contentClass: 'ms-form-table-input-trigger' }"
|
||||
:allow-clear="props.allowClear"
|
||||
@input="(val) => emit('input', val)"
|
||||
@change="(val) => emit('change', val)"
|
||||
/>
|
||||
<a-textarea
|
||||
v-else
|
||||
ref="inputRef"
|
||||
v-model:model-value="modelValue"
|
||||
:class="props.class"
|
||||
:disabled="props.disabled"
|
||||
:size="props.size"
|
||||
:placeholder="props.placeholder"
|
||||
:max-length="props.maxLength"
|
||||
:auto-size="{ minRows: 1, maxRows: 1 }"
|
||||
:allow-clear="props.allowClear"
|
||||
@input="(val) => emit('input', val)"
|
||||
@change="(val) => emit('change', val)"
|
||||
/>
|
||||
</a-popover>
|
||||
<a-modal
|
||||
v-model:visible="showQuickInput"
|
||||
:title="props.title"
|
||||
:ok-text="t('common.save')"
|
||||
:ok-button-props="{ disabled: !quickInputValue || quickInputValue.trim() === '' }"
|
||||
class="ms-modal-form"
|
||||
body-class="!p-0"
|
||||
:width="480"
|
||||
title-align="start"
|
||||
@ok="applyQuickInputDesc"
|
||||
@close="clearQuickInputDesc"
|
||||
>
|
||||
<a-textarea
|
||||
v-model:model-value="quickInputValue"
|
||||
:placeholder="props.placeholder"
|
||||
:auto-size="{ minRows: 2 }"
|
||||
:max-length="1000"
|
||||
></a-textarea>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useEventListener } from '@vueuse/core';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
type?: 'input' | 'textarea';
|
||||
title?: string;
|
||||
placeholder?: string;
|
||||
disabled?: boolean;
|
||||
size?: 'small' | 'large' | 'medium' | 'mini';
|
||||
maxLength?: number;
|
||||
class?: string;
|
||||
allowClear?: boolean;
|
||||
}>(),
|
||||
{
|
||||
type: 'input',
|
||||
title: '',
|
||||
disabled: false,
|
||||
size: 'medium',
|
||||
maxLength: 255,
|
||||
}
|
||||
);
|
||||
const emit = defineEmits<{
|
||||
(e: 'input', val: string): void;
|
||||
(e: 'change', val: string): void;
|
||||
(e: 'dblclick'): void;
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const modelValue = defineModel<string>('modelValue', {
|
||||
default: '',
|
||||
});
|
||||
|
||||
const inputRef = ref<HTMLElement>();
|
||||
const showQuickInput = ref(false);
|
||||
const quickInputValue = ref('');
|
||||
|
||||
function quickInputDesc() {
|
||||
showQuickInput.value = true;
|
||||
quickInputValue.value = modelValue.value;
|
||||
}
|
||||
|
||||
function clearQuickInputDesc() {
|
||||
quickInputValue.value = '';
|
||||
}
|
||||
|
||||
function applyQuickInputDesc() {
|
||||
modelValue.value = quickInputValue.value;
|
||||
emit('change', quickInputValue.value);
|
||||
clearQuickInputDesc();
|
||||
showQuickInput.value = false;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
useEventListener(inputRef.value, 'dblclick', () => {
|
||||
quickInputDesc();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.param-input:not(.arco-input-focus) {
|
||||
&:not(:hover) {
|
||||
@apply bg-transparent;
|
||||
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
.param-popover-title {
|
||||
@apply font-medium;
|
||||
|
||||
margin-bottom: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 16px;
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
.param-popover-value {
|
||||
min-width: 100px;
|
||||
max-width: 280px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
</style>
|
|
@ -399,6 +399,10 @@
|
|||
(val) => {
|
||||
if (typeof val === 'boolean') {
|
||||
treeRef.value?.expandAll(val);
|
||||
filterTreeData.value = mapTree(filterTreeData.value, (node) => {
|
||||
node.expanded = val;
|
||||
return node;
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -72,8 +72,6 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineModel } from 'vue';
|
||||
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import MsTag from '../ms-tag/ms-tag.vue';
|
||||
import FilterForm from './FilterForm.vue';
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineModel } from 'vue';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
import { validateJIRAKey } from '@/api/modules/project-management/menuManagement';
|
||||
|
|
|
@ -293,7 +293,6 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineModel, nextTick, onMounted, ref, useAttrs, watch } from 'vue';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
<template #content>
|
||||
<div class="mb-2 flex items-center justify-between">
|
||||
<div class="font-medium text-[var(--color-text-1)]">{{ t('msTable.columnSetting.display') }}</div>
|
||||
<MsButton :disabled="!hasChange" @click="handleReset">{{ t('msTable.columnSetting.resetDefault') }}</MsButton>
|
||||
<MsButton v-if="!props.onlyPageSize" :disabled="!hasChange" @click="handleReset">
|
||||
{{ t('msTable.columnSetting.resetDefault') }}
|
||||
</MsButton>
|
||||
</div>
|
||||
<template v-if="props.showPagination">
|
||||
<div class="font-medium text-[var(--color-text-4)]">{{ t('msTable.columnSetting.pageSize') }} </div>
|
||||
|
|
|
@ -165,8 +165,8 @@ export default {
|
|||
'common.resourceDeleted': '资源已被删除',
|
||||
'common.resourceExpired': '链接已失效,请重新获取',
|
||||
'common.refresh': '刷新',
|
||||
'common.searchByIdName': '通过ID 或名称搜索',
|
||||
'common.searchByIDNameTag': '通过ID、名称或标签搜索',
|
||||
'common.searchByIdName': '通过 ID/名称搜索',
|
||||
'common.searchByIDNameTag': '通过 ID/名称/标签搜索',
|
||||
'common.archive': '归档',
|
||||
'common.running': '执行中',
|
||||
'common.unExecute': '未执行',
|
||||
|
|
|
@ -595,13 +595,13 @@
|
|||
body-class="!p-0"
|
||||
:width="480"
|
||||
title-align="start"
|
||||
:auto-size="{ minRows: 2 }"
|
||||
@ok="applyQuickInputDesc"
|
||||
@close="clearQuickInputDesc"
|
||||
>
|
||||
<a-textarea
|
||||
v-model:model-value="quickInputDescValue"
|
||||
:placeholder="t('apiTestDebug.descPlaceholder')"
|
||||
:auto-size="{ minRows: 2 }"
|
||||
:max-length="1000"
|
||||
></a-textarea>
|
||||
</a-modal>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
export default {
|
||||
'apiTestDebug.newApi': '新建请求',
|
||||
'apiTestDebug.importApi': '导入请求',
|
||||
'apiTestDebug.urlPlaceholder': '请输入包含 http 或 https 的完整URL',
|
||||
'apiTestDebug.urlPlaceholder': '请输入包含 http/https 的完整URL',
|
||||
'apiTestDebug.definitionUrlPlaceholder': '输入接口URL,以“/”开始',
|
||||
'apiTestDebug.serverExec': '服务端执行',
|
||||
'apiTestDebug.localExec': '本地执行',
|
||||
|
|
|
@ -146,7 +146,7 @@ export default {
|
|||
'apiTestManagement.quoteType': '引用类型',
|
||||
'apiTestManagement.belongOrg': '所属组织',
|
||||
'apiTestManagement.belongProject': '所属项目',
|
||||
'apiTestManagement.quoteSearchPlaceholder': '输入 ID 或名称搜索',
|
||||
'apiTestManagement.quoteSearchPlaceholder': '输入 ID/名称搜索',
|
||||
'apiTestManagement.click': '点击',
|
||||
'apiTestManagement.getResponse': '获取响应内容',
|
||||
'apiTestManagement.tableNoDataAndPlease': '暂无数据,请',
|
||||
|
|
|
@ -41,7 +41,7 @@ export default {
|
|||
'apiScenario.params.csvQuoteAllow': '允许带引号',
|
||||
'apiScenario.params.csvRecycle': '遇到文件结束符再次循环',
|
||||
'apiScenario.params.csvStop': '遇到文件结束符停止线程',
|
||||
'apiScenario.params.searchPlaceholder': '通过名称或标签搜索',
|
||||
'apiScenario.params.searchPlaceholder': '通过名称/标签搜索',
|
||||
'apiScenario.params.priority':
|
||||
'变量优先级:临时参数>场景参数 >环境参数>全局参数;注: 避免使用同名变量,同名变量时场景级 CSV 优先级最高',
|
||||
'apiScenario.params.name': '变量名称',
|
||||
|
|
|
@ -168,7 +168,6 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineModel, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
|
|
@ -119,7 +119,7 @@ export default {
|
|||
permanentlyDeleteTip: '是否彻底删除 {name} 缺陷?',
|
||||
deleteContent: '删除后,缺陷无法恢复,请谨慎操作!',
|
||||
batchDelete: '是否彻底删除{count}条缺陷?',
|
||||
searchPlaceholder: '通过 ID 或名称搜索',
|
||||
searchPlaceholder: '通过 ID/名称搜索',
|
||||
deleteTime: '删除时间',
|
||||
deleteMan: '删除人',
|
||||
},
|
||||
|
|
|
@ -13,8 +13,8 @@ export default {
|
|||
'caseManagement.featureCase.rename': '重命名',
|
||||
'caseManagement.featureCase.recycle': '回收站',
|
||||
'caseManagement.featureCase.versionPlaceholder': '默认为最新版本',
|
||||
'caseManagement.featureCase.searchByNameAndId': '通过ID、名称或标签搜索',
|
||||
'caseManagement.featureCase.searchByIdAndName': '通过ID 或名称搜索',
|
||||
'caseManagement.featureCase.searchByNameAndId': '通过 ID/名称/标签搜索',
|
||||
'caseManagement.featureCase.searchByIdAndName': '通过 ID/名称搜索',
|
||||
'caseManagement.featureCase.searchByName': '通过名称搜索',
|
||||
'caseManagement.featureCase.filter': '筛选',
|
||||
'caseManagement.featureCase.setFilterCondition': '设置筛选条件',
|
||||
|
|
|
@ -2,8 +2,8 @@ export default {
|
|||
'caseManagement.caseReview.create': '创建评审',
|
||||
'caseManagement.caseReview.waitMyReview': '我评审的',
|
||||
'caseManagement.caseReview.myCreate': '我创建的',
|
||||
'caseManagement.caseReview.searchPlaceholder': '通过 ID 或名称搜索',
|
||||
'caseManagement.caseReview.list.searchPlaceholder': '通过ID、名称或标签搜索',
|
||||
'caseManagement.caseReview.searchPlaceholder': '通过 ID/名称搜索',
|
||||
'caseManagement.caseReview.list.searchPlaceholder': '通过 ID/名称/标签搜索',
|
||||
'caseManagement.caseReview.archive': '归档',
|
||||
'caseManagement.caseReview.tableNoData': '暂无数据,请',
|
||||
'caseManagement.caseReview.tableNoDataNoPermission': '暂无数据',
|
||||
|
|
|
@ -44,7 +44,7 @@ export default {
|
|||
'project.commonScript.commonScriptList': '公共脚本列表',
|
||||
'project.commonScript.folderSearchPlaceholder': '请输入模块名称',
|
||||
'project.commonScript.allApis': '全部接口',
|
||||
'project.commonScript.searchPlaceholder': '通过 ID 或名称搜索',
|
||||
'project.commonScript.searchPlaceholder': '通过 ID/名称搜索',
|
||||
'project.commonScript.noTreeData': '暂无接口数据',
|
||||
'project.commonScript.apiName': '接口名称',
|
||||
'project.commonScript.requestType': '请求类型',
|
||||
|
|
|
@ -67,7 +67,6 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineModel, ref } from 'vue';
|
||||
import { type FileItem, Message } from '@arco-design/web-vue';
|
||||
|
||||
import MsUpload from '@/components/pure/ms-upload/index.vue';
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineModel, onBeforeMount, ref } from 'vue';
|
||||
import { VueDraggable } from 'vue-draggable-plus';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
type UserModalMode = 'create' | 'edit';
|
||||
const batchFormModels: Ref<FormItemModel[]> = ref([
|
||||
{
|
||||
filed: 'ip',
|
||||
field: 'ip',
|
||||
type: 'input',
|
||||
label: 'project.environmental.host.ip',
|
||||
placeholder: 'project.environmental.host.ipPlaceholder',
|
||||
|
@ -84,14 +84,14 @@
|
|||
],
|
||||
},
|
||||
{
|
||||
filed: 'domain',
|
||||
field: 'domain',
|
||||
type: 'input',
|
||||
label: 'project.environmental.host.hostName',
|
||||
placeholder: 'project.environmental.host.hostNamePlaceholder',
|
||||
rules: [{ required: true, message: t('project.environmental.host.hostNameIsRequire') }],
|
||||
},
|
||||
{
|
||||
filed: 'description',
|
||||
field: 'description',
|
||||
type: 'input',
|
||||
label: 'common.desc',
|
||||
placeholder: 'project.environmental.host.descPlaceholder',
|
||||
|
|
|
@ -224,12 +224,9 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineModel } from 'vue';
|
||||
import { Message, ValidatedError } from '@arco-design/web-vue';
|
||||
|
||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||
import type { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||
import type { MsTreeNodeData } from '@/components/business/ms-tree/types';
|
||||
|
||||
import { getEnvModules } from '@/api/modules/api-test/management';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
|
|
@ -15,7 +15,7 @@ export default {
|
|||
'project.environmental.supportFormat': '仅支持MeterSphere导出的Json文件,单个大小不超过 50M',
|
||||
'project.environmental.importTile': '注意!导入后会覆盖原全局参数',
|
||||
'project.environmental.mustContain': '必含',
|
||||
'project.environmental.searchParamsHolder': '通过名称或标签搜索',
|
||||
'project.environmental.searchParamsHolder': '通过名称/标签搜索',
|
||||
'project.environmental.paramName': '参数名称',
|
||||
'project.environmental.paramNamePlaceholder': '请输入参数名称',
|
||||
'project.environmental.paramType': '类型',
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="mb-4 flex items-center justify-between">
|
||||
<a-button v-permission="['PROJECT_APPLICATION_API:UPDATE']" type="primary" @click="showAddRule(undefined)">{{
|
||||
t('project.menu.addFalseAlertRules')
|
||||
}}</a-button>
|
||||
<a-button v-permission="['PROJECT_APPLICATION_API:UPDATE']" type="primary" @click="showAddRule(undefined)">
|
||||
{{ t('project.menu.addFalseAlertRules') }}
|
||||
</a-button>
|
||||
<a-input-search
|
||||
v-model="keyword"
|
||||
:placeholder="t('project.menu.nameSearch')"
|
||||
|
@ -29,9 +29,9 @@
|
|||
<template v-if="!record.enable">
|
||||
<div class="flex flex-row">
|
||||
<span v-permission="['PROJECT_APPLICATION_API:UPDATE']" class="flex flex-row">
|
||||
<MsButton class="!mr-0" @click="handleEnableOrDisableProject(record.id)">{{
|
||||
t('common.enable')
|
||||
}}</MsButton>
|
||||
<MsButton class="!mr-0" @click="handleEnableOrDisableProject(record.id)">
|
||||
{{ t('common.enable') }}
|
||||
</MsButton>
|
||||
<a-divider direction="vertical" />
|
||||
</span>
|
||||
<span>
|
||||
|
@ -50,9 +50,9 @@
|
|||
<a-divider class="h-[16px]" direction="vertical" />
|
||||
</span>
|
||||
<span v-permission="['PROJECT_APPLICATION_API:UPDATE']" class="flex flex-row items-center">
|
||||
<MsButton class="!mr-0" @click="handleEnableOrDisableProject(record.id, false)">{{
|
||||
t('common.disable')
|
||||
}}</MsButton>
|
||||
<MsButton class="!mr-0" @click="handleEnableOrDisableProject(record.id, false)">
|
||||
{{ t('common.disable') }}
|
||||
</MsButton>
|
||||
<a-divider class="h-[16px]" direction="vertical" />
|
||||
</span>
|
||||
<MsTableMoreAction
|
||||
|
@ -174,7 +174,7 @@
|
|||
};
|
||||
const initBatchFormModels: FormItemModel[] = [
|
||||
{
|
||||
filed: 'name',
|
||||
field: 'name',
|
||||
type: 'input',
|
||||
label: 'project.menu.rule.ruleName',
|
||||
rules: [
|
||||
|
@ -183,34 +183,35 @@
|
|||
],
|
||||
},
|
||||
{
|
||||
filed: 'type',
|
||||
field: 'type',
|
||||
type: 'tagInput',
|
||||
label: 'project.menu.rule.label',
|
||||
},
|
||||
{
|
||||
filed: 'rule',
|
||||
field: 'rule',
|
||||
type: 'multiple',
|
||||
label: 'project.menu.rule.rule',
|
||||
hasRedStar: true,
|
||||
children: [
|
||||
{
|
||||
filed: 'respType', // 匹配规则-内容类型/header/data/body
|
||||
field: 'respType', // 匹配规则-内容类型/header/data/body
|
||||
type: 'select',
|
||||
options: headerOptions.value,
|
||||
className: 'w-[205px]',
|
||||
defaultValue: 'RESPONSE_HEADERS',
|
||||
},
|
||||
{
|
||||
filed: 'relation', // 匹配规则-操作类型
|
||||
field: 'relation', // 匹配规则-操作类型
|
||||
type: 'select',
|
||||
options: relationOptions.value,
|
||||
defaultValue: 'CONTAINS',
|
||||
className: 'w-[120px]',
|
||||
},
|
||||
{
|
||||
filed: 'expression', // 匹配规则-表达式
|
||||
type: 'input',
|
||||
field: 'expression', // 匹配规则-表达式
|
||||
type: 'textarea',
|
||||
rules: [{ required: true, message: t('project.menu.rule.expressionNotNull') }],
|
||||
title: t('project.menu.rule.ruleExpression'),
|
||||
className: 'w-[301px]',
|
||||
},
|
||||
],
|
||||
|
@ -410,7 +411,7 @@
|
|||
addVisible.value = true;
|
||||
};
|
||||
|
||||
const handleCancel = (shouldSearch: boolean, isClose = true) => {
|
||||
const handleCancel = (shouldSearch: boolean) => {
|
||||
if (shouldSearch) {
|
||||
fetchData();
|
||||
}
|
||||
|
@ -441,7 +442,7 @@
|
|||
Message.success(t('common.updateSuccess'));
|
||||
}
|
||||
|
||||
handleCancel(true, false);
|
||||
handleCancel(true);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
export default {
|
||||
'project.menu.management': 'Application Setting',
|
||||
'project.menu.management': 'Application Settings',
|
||||
'project.menu.manageTip':
|
||||
'You can configure the switch of each function according to the usage scenario. After closing, the function entry will be hidden, and members cannot access this function and data; the data already generated will not be affected by this rule; when it is turned on again, it will be restored to the state before closing',
|
||||
'You can configure various feature switches based on usage scenarios. After closing them, the corresponding feature entry will be hidden and members will not be able to access the feature and its data. The rule does not affect existing data. When you reopen it, it will restore to the state before closing.',
|
||||
'project.menu.name': 'Menu Name',
|
||||
'project.menu.pleaseConfig': 'Please Configure',
|
||||
'project.menu.count': 'Items',
|
||||
'project.menu.pleaseConfig': 'Please configure',
|
||||
'project.menu.count': 'Count',
|
||||
|
||||
'project.menu.WORKSTATION_SYNC_RULE': 'Interface Test Update Synchronization Rule',
|
||||
'project.menu.TEST_PLAN_CLEAN_REPORT': 'Report Retention Time Range',
|
||||
|
@ -12,69 +12,95 @@ export default {
|
|||
'project.menu.UI_CLEAN_REPORT': 'Report Retention Time Range',
|
||||
'project.menu.UI_SHARE_REPORT': 'Report Link Validity Period',
|
||||
'project.menu.UI_RESOURCE_POOL': 'Execution Resource Pool',
|
||||
'project.menu.UI_RESOURCE_POOL_TIP': 'The current resource pool is: {name}; you can switch resource pools',
|
||||
'project.menu.UI_RESOURCE_POOL_TIP': 'The current resource pool in use is: {name}; you can switch resource pools',
|
||||
'project.menu.PERFORMANCE_TEST_CLEAN_REPORT': 'Report Retention Time Range',
|
||||
'project.menu.PERFORMANCE_TEST_SHARE_REPORT': 'Report Link Validity Period',
|
||||
'project.menu.PERFORMANCE_TEST_SCRIPT_REVIEWER': 'Script Review',
|
||||
'project.menu.PERFORMANCE_TEST_SCRIPT_REVIEWER': 'Script Reviewer',
|
||||
'project.menu.PERFORMANCE_TEST_SCRIPT_REVIEWER_TIP':
|
||||
'The interface case contains script steps that need to be reviewed by a designated user; the reviewer can be changed',
|
||||
'project.menu.API_URL_REPEATABLE': 'Interface API URL Can Be Repeated',
|
||||
'Specify a user to review script steps in interface test cases; you can change the reviewer',
|
||||
'project.menu.API_URL_REPEATABLE': 'API Definition URL Repeatability',
|
||||
'project.menu.API_CLEAN_REPORT': 'Report Retention Time Range',
|
||||
'project.menu.API_SHARE_REPORT': 'Report Link Validity Period',
|
||||
'project.menu.API_RESOURCE_POOL': 'Execution Resource Pool',
|
||||
'project.menu.API_RESOURCE_POOL_TIP': 'Execution machine for interface testing',
|
||||
'project.menu.API_SCRIPT_REVIEWER': 'Script Review',
|
||||
'project.menu.API_SCRIPT_REVIEWER': 'Script Reviewer',
|
||||
'project.menu.API_SCRIPT_REVIEWER_TIP':
|
||||
'The interface case contains script steps that need to be reviewed by a designated user; the reviewer can be changed',
|
||||
'project.menu.API_ERROR_REPORT_RULE': 'Fake Error Rule',
|
||||
'Specify a user to review script steps in interface test cases; you can change the reviewer',
|
||||
'project.menu.API_ERROR_REPORT_RULE': 'False Alert Rule',
|
||||
'project.menu.API_ERROR_REPORT_RULE_TIP':
|
||||
'When the interface return result matches the fake error rule, the interface result will be treated as a false report',
|
||||
'project.menu.API_SYNC_CASE': 'Change Sync CASE',
|
||||
'When the interface returns a result that matches the false alert rule, the interface result will be treated as a false alert',
|
||||
'project.menu.API_SYNC_CASE': 'Change Synchronized CASE',
|
||||
|
||||
'project.menu.CASE_PUBLIC': 'Public Case Library',
|
||||
'project.menu.CASE_RE_REVIEW': 'Resubmit for Review',
|
||||
'project.menu.CASE_PUBLIC': 'Public Test Case Library',
|
||||
'project.menu.CASE_RE_REVIEW': 'Re-review',
|
||||
'project.menu.CASE_RELATED': 'Related Requirements',
|
||||
'project.menu.BUG_SYNC': 'Sync Defects',
|
||||
'project.menu.BUG_SYNC': 'Defect Synchronization',
|
||||
'project.menu.SYNC_ENABLE': 'Status',
|
||||
'project.menu.MECHANISM': 'Interface Test Update Synchronization Rule',
|
||||
'project.menu.row1': 'The system displays the data that meets the set rules in my to-do list-to be updated',
|
||||
'project.menu.row2': 'Sync the defects created by the platform to the third-party project management platform',
|
||||
'project.menu.row3': 'You can add cases to the public case library for shared use',
|
||||
'project.menu.row4': 'You can associate cases with third-party project management platforms',
|
||||
'project.menu.row1': 'The system displays data that meets the rules in My To-Do List - To Be Updated',
|
||||
'project.menu.row2': 'Synchronize defects created on the platform to third-party project management platforms',
|
||||
'project.menu.row3': 'Add test cases to the public test case library for sharing',
|
||||
'project.menu.row4': 'Associate test cases with third-party project management platforms',
|
||||
'project.menu.row5':
|
||||
'When the case changes during the review activity, the case status automatically switches to resubmit for review',
|
||||
'project.menu.row6': 'After turning on, the interface definition module repetitiveness check will not check the URL',
|
||||
'project.menu.row7': 'When the interface definition changes, the interface CASE is automatically synchronized',
|
||||
'project.menu.notConfig': 'Third-party information is not configured, click',
|
||||
'When changes occur in test cases during the review process, the test case status automatically switches to re-review',
|
||||
'project.menu.row6': 'When enabled, the interface definition module will not validate URL duplication',
|
||||
'project.menu.row7': 'Automatically synchronize interface CASE when the interface definition changes',
|
||||
'project.menu.notConfig': 'Third-party information not configured, click',
|
||||
'project.menu.configure': 'to configure',
|
||||
'project.menu.status': 'Status',
|
||||
'project.menu.incrementalSync': 'Incremental Sync',
|
||||
'project.menu.incrementalSyncTip': 'Only the contents of the three-party bug existing in MS are changed',
|
||||
'project.menu.fullSync': 'Full Sync',
|
||||
'project.menu.fullSyncTip': 'Fully sync bug of third-party platforms to MS',
|
||||
'project.menu.incrementalSync': 'Incremental Synchronization',
|
||||
'project.menu.incrementalSyncTip': 'Only make content changes to existing third-party defects in MS',
|
||||
'project.menu.fullSync': 'Full Synchronization',
|
||||
'project.menu.fullSyncTip': 'Fully synchronize defects from third-party platforms to MS',
|
||||
'project.menu.platformPlaceholder':
|
||||
'No third-party platform integrated yet, please contact the organization administrator to integrate',
|
||||
'Third-party platform not integrated yet, please contact the organization administrator for integration',
|
||||
'project.menu.platformLabel': 'Third-party Project Management Platform',
|
||||
'project.menu.syncMechanism': 'Sync Mechanism',
|
||||
'project.menu.CRON_EXPRESSION': 'Sync Frequency',
|
||||
'project.menu.syncMechanism': 'Synchronization Mechanism',
|
||||
'project.menu.CRON_EXPRESSION': 'Synchronization Frequency',
|
||||
'project.menu.projectKey': 'Project Key',
|
||||
'project.menu.projectId': 'Project ID',
|
||||
'project.menu.organizationId': 'Organization ID',
|
||||
'project.menu.azureId': 'Azure Filter ID',
|
||||
'project.menu.defectType': 'Defect Type',
|
||||
'project.menu.demandType': 'Demand Type',
|
||||
'project.menu.howGetJiraKey': 'How to get JIRA project key',
|
||||
'project.menu.demandType': 'Requirement Type',
|
||||
'project.menu.howGetJiraKey': 'How to Get JIRA Project Key',
|
||||
'project.menu.preview': 'Preview',
|
||||
'project.menu.pleaseInputJiraKey': 'Please enter JIRA project key',
|
||||
'project.menu.addFalseAlertRules': 'Add False Alert Rules',
|
||||
'project.menu.updateFalseAlertRules': 'update False Alert Rules',
|
||||
'project.menu.addFalseAlertRules': 'Add False Alert Rule',
|
||||
'project.menu.updateFalseAlertRules': 'Update False Alert Rule',
|
||||
'project.menu.nameSearch': 'Search by Name',
|
||||
// Sync defects
|
||||
// Defect Synchronization
|
||||
'project.menu.defect.enableTip':
|
||||
'Turn on: The defects created by the platform are synced to the third-party project management platform',
|
||||
'Enable: Synchronize defects created on the platform to third-party project management platforms',
|
||||
'project.menu.defect.closeTip':
|
||||
'Turn off: The defects created by the platform cannot be synced to the third-party project management platform',
|
||||
'project.menu.demand.enableTip': 'On: functional cases can relate to third-party demands',
|
||||
'project.menu.demand.closeTip': 'Off: functional cases cannot relate to third party demands',
|
||||
'Disable: Defects created on the platform will not be synchronized to third-party project management platforms',
|
||||
'project.menu.demand.enableTip':
|
||||
'Enable: Test cases created on the platform can be associated with third-party requirements',
|
||||
'project.menu.demand.closeTip':
|
||||
'Disable: Test cases created on the platform cannot be associated with third-party requirements',
|
||||
'project.menu.defect.customLabel': 'Custom Frequency',
|
||||
'project.menu.defect.enableAfterConfig': 'Enable after configuring third-party information',
|
||||
// False Alert Rule
|
||||
'project.menu.rule.name': 'Name',
|
||||
'project.menu.rule.enable': 'Status',
|
||||
'project.menu.rule.label': 'Label',
|
||||
'project.menu.rule.rule': 'Rule',
|
||||
'project.menu.rule.creator': 'Creator',
|
||||
'project.menu.rule.updateTime': 'Update Time',
|
||||
'project.menu.rule.operation': 'Operation',
|
||||
'project.menu.rule.ruleName': 'Rule Name',
|
||||
'project.menu.rule.ruleExpression': 'Rule condition',
|
||||
'project.menu.rule.ruleNameNotNull': 'Rule name cannot be empty',
|
||||
'project.menu.rule.ruleNameRepeat': 'Please modify the duplicate name',
|
||||
'project.menu.rule.expressionNotNull': 'Limiting condition cannot be empty',
|
||||
'project.menu.rule.addRule': 'Add Rule',
|
||||
'project.menu.rule.disableRule': 'Disable Rule',
|
||||
'project.menu.rule.disableRuleTip':
|
||||
'After disabling, the interface result will no longer match this false alert rule.',
|
||||
'project.menu.rule.enableRule': 'Enable Rule',
|
||||
'project.menu.rule.enableRuleTip':
|
||||
'After enabling, the interface result will be matched against the false alert rule first.',
|
||||
'project.menu.rule.deleteRule': 'Confirm to delete {size} false alert rules?',
|
||||
'project.menu.rule.deleteRuleTip':
|
||||
'After deletion, it only takes effect on newly executed test reports. Please be cautious!',
|
||||
};
|
||||
|
|
|
@ -80,6 +80,7 @@ export default {
|
|||
'project.menu.rule.updateTime': '更新时间',
|
||||
'project.menu.rule.operation': '操作',
|
||||
'project.menu.rule.ruleName': '规则名称',
|
||||
'project.menu.rule.ruleExpression': '限制条件',
|
||||
'project.menu.rule.ruleNameNotNull': '规则名称不能为空',
|
||||
'project.menu.rule.ruleNameRepeat': '名称重复请修改',
|
||||
'project.menu.rule.expressionNotNull': '限制条件不能为空',
|
||||
|
|
|
@ -15,7 +15,7 @@ export default {
|
|||
'project.projectVersion.publishTime': '发布时间',
|
||||
'project.projectVersion.createTime': '创建时间',
|
||||
'project.projectVersion.creator': '创建人',
|
||||
'project.projectVersion.searchPlaceholder': '通过ID/名称搜索',
|
||||
'project.projectVersion.searchPlaceholder': '通过 ID/名称搜索',
|
||||
'project.projectVersion.quickCreate': '快速创建版本',
|
||||
'project.projectVersion.versionNamePlaceholder': '请输入版本名称',
|
||||
'project.projectVersion.versionNameRequired': '版本名称不能为空',
|
||||
|
|
|
@ -212,7 +212,7 @@
|
|||
|
||||
// 批量表单-1.仅选项情况
|
||||
const onlyOptions: Ref<FormItemModel> = ref({
|
||||
filed: 'text',
|
||||
field: 'text',
|
||||
type: 'input',
|
||||
label: '',
|
||||
rules: [
|
||||
|
@ -227,7 +227,7 @@
|
|||
// 批量表单-2 缺陷情况
|
||||
const bugBatchFormRules = ref<FormItemModel[]>([
|
||||
{
|
||||
filed: 'text',
|
||||
field: 'text',
|
||||
type: 'input',
|
||||
label: '',
|
||||
rules: [
|
||||
|
@ -239,7 +239,7 @@
|
|||
hideLabel: true,
|
||||
},
|
||||
{
|
||||
filed: 'value',
|
||||
field: 'value',
|
||||
type: 'input',
|
||||
label: '',
|
||||
rules: [
|
||||
|
|
|
@ -50,7 +50,7 @@ export default {
|
|||
'system.organization.updateOrganizationSuccess': '更新组织成功',
|
||||
'system.organization.createProject': '创建项目',
|
||||
'system.organization.subordinateOrg': '所属组织',
|
||||
'system.organization.searchIndexPlaceholder': '通过ID/名称搜索',
|
||||
'system.organization.searchIndexPlaceholder': '通过 ID/名称搜索',
|
||||
'system.organization.searchUserPlaceholder': '通过名称/邮箱/手机搜索',
|
||||
'system.organization.organizationAdminRequired': '组织管理员不能为空',
|
||||
'system.project.enableTitle': '启用项目',
|
||||
|
@ -73,7 +73,7 @@ export default {
|
|||
'system.organization.projectIsDisabled': '项目已结束,可在 项目列表 启用',
|
||||
'system.project.deleteName': '确认删除 {name} 这个项目吗?',
|
||||
'system.project.deleteTip': '删除后,系统会在 30天 后执行删除项目 (含项目下所有业务数据),请谨慎操作!',
|
||||
'system.project.searchPlaceholder': '通过ID或项目名称搜索',
|
||||
'system.project.searchPlaceholder': '通过 ID/项目名称搜索',
|
||||
'system.project.afterModule': '取消模块后用户将无法进入指定模块,已存在的数据会继续保留',
|
||||
'system.project.projectAdminIsNotNull': '项目管理员不能为空',
|
||||
'system.project.pleaseSelectAdmin': '请选择项目管理员',
|
||||
|
|
|
@ -574,21 +574,21 @@
|
|||
const batchFormRef = ref<InstanceType<typeof MsBatchForm>>();
|
||||
const batchFormModels: Ref<FormItemModel[]> = ref([
|
||||
{
|
||||
filed: 'ip',
|
||||
field: 'ip',
|
||||
type: 'input',
|
||||
label: 'system.resourcePool.ip',
|
||||
rules: [{ required: true, message: t('system.resourcePool.ipRequired') }],
|
||||
placeholder: 'system.resourcePool.ipPlaceholder',
|
||||
},
|
||||
{
|
||||
filed: 'port',
|
||||
field: 'port',
|
||||
type: 'input',
|
||||
label: 'system.resourcePool.port',
|
||||
rules: [{ required: true, message: t('system.resourcePool.portRequired') }],
|
||||
placeholder: 'system.resourcePool.portPlaceholder',
|
||||
},
|
||||
{
|
||||
filed: 'concurrentNumber',
|
||||
field: 'concurrentNumber',
|
||||
type: 'inputNumber',
|
||||
label: 'system.resourcePool.concurrentNumber',
|
||||
rules: [
|
||||
|
|
|
@ -834,14 +834,14 @@
|
|||
const batchFormRef = ref<InstanceType<typeof MsBatchForm>>();
|
||||
const batchFormModels: Ref<FormItemModel[]> = ref([
|
||||
{
|
||||
filed: 'name',
|
||||
field: 'name',
|
||||
type: 'input',
|
||||
label: 'system.user.createUserName',
|
||||
rules: [{ required: true, message: t('system.user.createUserNameNotNull') }, { validator: checkUerName }],
|
||||
placeholder: 'system.user.createUserNamePlaceholder',
|
||||
},
|
||||
{
|
||||
filed: 'email',
|
||||
field: 'email',
|
||||
type: 'input',
|
||||
label: 'system.user.createUserEmail',
|
||||
rules: [
|
||||
|
@ -852,7 +852,7 @@
|
|||
placeholder: 'system.user.createUserEmailPlaceholder',
|
||||
},
|
||||
{
|
||||
filed: 'phone',
|
||||
field: 'phone',
|
||||
type: 'input',
|
||||
label: 'system.user.createUserPhone',
|
||||
rules: [{ validator: checkUerPhone }],
|
||||
|
|
|
@ -37,7 +37,7 @@ export default {
|
|||
pleaseInputUserGroupName: '请输入用户组名称,且不与其他用户组名称重复',
|
||||
userGroupNameIsExist: `已有 {name} ,请更改`,
|
||||
pleaseSelectAuthScope: '请选择用户组所属的权限范围',
|
||||
searchPlaceholder: '通过ID/名称搜索',
|
||||
searchPlaceholder: '通过 ID/名称搜索',
|
||||
SYSTEM: '系统',
|
||||
PROJECT: '项目',
|
||||
ORGANIZATION: '组织',
|
||||
|
|
|
@ -111,7 +111,7 @@ export default {
|
|||
'testPlan.featureCase.richTextDblclickPlaceholder': '双击可全屏输入',
|
||||
'testPlan.featureCase.autoNextTip1': '开启:提交结果后,跳转至下一条用例',
|
||||
'testPlan.featureCase.autoNextTip2': '关闭:提交结果后,还在当前',
|
||||
'testPlan.api.testSetRequired': '测试集不能为空',
|
||||
'testPlan.api.testSetRequired': '测试点不能为空',
|
||||
'testPlan.executeHistory.executionStartAndEndTime': '执行起止时间',
|
||||
'testPlan.executeHistory.testPlanHasTimedOut': '测试计划已超时',
|
||||
'testPlan.testPlanGroup.seeArchived': '只看已归档',
|
||||
|
@ -134,6 +134,6 @@ export default {
|
|||
'testPlan.testPlanGroup.enableScheduleTaskSuccess': '开启定时任务成功',
|
||||
'testPlan.testPlanGroup.closeScheduleTaskSuccess': '关闭定时任务成功',
|
||||
'testPlan.plan': '测试规划',
|
||||
'testPlan.planTip': '1.创建测试集进行业务分类测试;2.选择测试集关联用例',
|
||||
'testPlan.planTip': '1.创建测试点进行业务分类测试;2.选择测试点关联用例',
|
||||
'testPlan.planStartToEndTimeTip': '测试计划已超时',
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue