fix(全局): 部分 bug 修复

This commit is contained in:
baiqi 2024-06-21 16:47:59 +08:00 committed by Craftsman
parent e4b1c29dc8
commit 413c7fc7b3
44 changed files with 542 additions and 208 deletions

View File

@ -188,8 +188,8 @@ export function saveCaseMinder(data: FeatureCaseMinderUpdateParams) {
} }
// 获取脑图 // 获取脑图
export function getCaseMinder(data: { projectId: string; moduleId: string }) { export function getCaseMinder(data: { projectId: string; moduleId: string; current: number }) {
return MSR.post<MinderJsonNode[]>({ url: `${GetCaseMinderUrl}`, data }); return MSR.post<CommonList<MinderJsonNode>>({ url: `${GetCaseMinderUrl}`, data });
} }
// 获取脑图模块树(包含文本节点) // 获取脑图模块树(包含文本节点)

View File

@ -370,6 +370,7 @@
.ms-scroll-bar(); .ms-scroll-bar();
padding-right: 16px; padding-right: 16px;
min-height: 30px;
} }
.arco-textarea-wrapper { .arco-textarea-wrapper {
resize: vertical !important; resize: vertical !important;

View File

@ -138,7 +138,6 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { defineModel } from 'vue';
import { useVModel } from '@vueuse/core'; import { useVModel } from '@vueuse/core';
import { cloneDeep } from 'lodash-es'; import { cloneDeep } from 'lodash-es';
import { VueDraggable } from 'vue-draggable-plus'; import { VueDraggable } from 'vue-draggable-plus';

View File

@ -7,14 +7,14 @@ export default {
'ms.case.associate.version': '版本', 'ms.case.associate.version': '版本',
'ms.case.associate.versionPlaceholder': '默认最新版本', 'ms.case.associate.versionPlaceholder': '默认最新版本',
'ms.case.associate.tags': '标签', 'ms.case.associate.tags': '标签',
'ms.case.associate.searchPlaceholder': '通过 ID名称搜索', 'ms.case.associate.searchPlaceholder': '通过 ID/名称搜索',
'ms.case.associate.associateSuccess': '关联成功', 'ms.case.associate.associateSuccess': '关联成功',
'ms.case.associate.functionalCase': '功能用例', 'ms.case.associate.functionalCase': '功能用例',
'ms.case.associate.apiCase': '接口用例', 'ms.case.associate.apiCase': '接口用例',
'ms.case.associate.apiScenarioCase': '接口场景用例', 'ms.case.associate.apiScenarioCase': '接口场景用例',
'ms.case.associate.UIScenario': 'UI场景用例', 'ms.case.associate.UIScenario': 'UI场景用例',
'ms.case.associate.performanceCase': '性能用例', 'ms.case.associate.performanceCase': '性能用例',
'ms.case.associate.testSet': '测试', 'ms.case.associate.testSet': '测试',
'ms.case.associate.addAssociatedCase': '添加已关联用例', 'ms.case.associate.addAssociatedCase': '添加已关联用例',
'ms.case.associate.automaticallyAddApiCase': '自动添加已关联的接口用例', 'ms.case.associate.automaticallyAddApiCase': '自动添加已关联的接口用例',
'ms.case.associate.project': '项目', 'ms.case.associate.project': '项目',

View File

@ -16,7 +16,7 @@
> >
<div <div
v-for="(element, index) in form.list" v-for="(element, index) in form.list"
:key="`${element.filed}${index}`" :key="`${element.field}${index}`"
class="draggableElement gap-[8px] py-[6px] pr-[8px]" class="draggableElement gap-[8px] py-[6px] pr-[8px]"
:class="[props.isShowDrag ? 'cursor-move' : '']" :class="[props.isShowDrag ? 'cursor-move' : '']"
> >
@ -25,14 +25,14 @@
/></div> /></div>
<a-form-item <a-form-item
v-for="model of props.models" v-for="model of props.models"
:key="`${model.filed}${index}`" :key="`${model.field}${index}`"
:field="`list[${index}].${model.filed}`" :field="`list[${index}].${model.field}`"
:class="index > 0 ? 'hidden-item' : 'mb-0 flex-1'" :class="index > 0 ? 'hidden-item' : 'mb-0 flex-1'"
:rules=" :rules="
model.rules?.map((e) => { model.rules?.map((e) => {
if (e.notRepeat === true) { if (e.notRepeat === true) {
return { 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; return e;
@ -59,17 +59,30 @@
</template> </template>
<a-input <a-input
v-if="model.type === 'input'" v-if="model.type === 'input'"
v-model:model-value="element[model.filed]" v-model:model-value="element[model.field]"
class="flex-1" class="flex-1"
:placeholder="t(model.placeholder || '')" :placeholder="t(model.placeholder || '')"
:max-length="model.maxLength || 255" :max-length="model.maxLength || 255"
allow-clear allow-clear
@change="emit('change')" @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-tooltip v-else-if="model.type === 'inputNumber'" position="tl" mini :disabled="!model.tooltip">
<a-input-number <a-input-number
v-if="model.type === 'inputNumber'" v-if="model.type === 'inputNumber'"
v-model:model-value="element[model.filed]" v-model:model-value="element[model.field]"
class="flex-1" class="flex-1"
:placeholder="t(model.placeholder || '')" :placeholder="t(model.placeholder || '')"
:min="model.min" :min="model.min"
@ -89,7 +102,7 @@
</a-tooltip> </a-tooltip>
<MsTagsInput <MsTagsInput
v-else-if="model.type === 'tagInput'" v-else-if="model.type === 'tagInput'"
v-model:model-value="element[model.filed]" v-model:model-value="element[model.field]"
class="flex-1" class="flex-1"
:placeholder="t(model.placeholder || 'common.tagPlaceholder')" :placeholder="t(model.placeholder || 'common.tagPlaceholder')"
allow-clear allow-clear
@ -100,7 +113,7 @@
/> />
<a-select <a-select
v-else-if="model.type === 'select'" v-else-if="model.type === 'select'"
v-model="element[model.filed]" v-model="element[model.field]"
class="flex-1" class="flex-1"
:placeholder="t(model.placeholder || '')" :placeholder="t(model.placeholder || '')"
:options="model.options" :options="model.options"
@ -110,8 +123,8 @@
<div v-else-if="model.type === 'multiple'" class="flex flex-row gap-[4px]"> <div v-else-if="model.type === 'multiple'" class="flex flex-row gap-[4px]">
<a-form-item <a-form-item
v-for="(child, childIndex) in model.children" v-for="(child, childIndex) in model.children"
:key="`${child.filed}${childIndex}${index}`" :key="`${child.field}${childIndex}${index}`"
:field="`list[${index}].${child.filed}`" :field="`list[${index}].${child.field}`"
:label="child.label ? t(child.label) : ''" :label="child.label ? t(child.label) : ''"
asterisk-position="end" asterisk-position="end"
:hide-asterisk="child.hideAsterisk" :hide-asterisk="child.hideAsterisk"
@ -121,7 +134,7 @@
> >
<a-input <a-input
v-if="child.type === 'input'" v-if="child.type === 'input'"
v-model="element[child.filed]" v-model="element[child.field]"
:class="child.className" :class="child.className"
:placeholder="t(child.placeholder || '')" :placeholder="t(child.placeholder || '')"
:max-length="child.maxLength || 255" :max-length="child.maxLength || 255"
@ -130,13 +143,29 @@
/> />
<a-select <a-select
v-else-if="child.type === 'select'" v-else-if="child.type === 'select'"
v-model="element[child.filed]" v-model="element[child.field]"
:class="child.className" :class="child.className"
:placeholder="t(child.placeholder || '')" :placeholder="t(child.placeholder || '')"
:options="child.options" :options="child.options"
:field-names="child.filedNames" :field-names="child.filedNames"
@change="emit('change')" @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> </a-form-item>
</div> </div>
</a-form-item> </a-form-item>
@ -199,6 +228,7 @@
import { VueDraggable } from 'vue-draggable-plus'; import { VueDraggable } from 'vue-draggable-plus';
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue'; 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 { useI18n } from '@/hooks/useI18n';
import { scrollIntoView } from '@/utils/dom'; import { scrollIntoView } from '@/utils/dom';
@ -253,19 +283,19 @@
} else { } else {
value = e.defaultValue; value = e.defaultValue;
} }
formItem[e.filed] = value; formItem[e.field] = value;
if (props.showEnable) { if (props.showEnable) {
// //
formItem.enable = false; formItem.enable = false;
} }
// //
e.children?.forEach((child) => { 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 }]; form.value.list = [{ ...formItem }];
if (props.defaultVals?.length) { if (props.defaultVals?.length) {
// defaultVals filed // defaultVals field
form.value.list = props.defaultVals.map((e) => e); form.value.list = props.defaultVals.map((e) => e);
} }
}); });

View File

@ -1,6 +1,6 @@
import { FieldRule, SelectFieldNames, SelectOptionData, SelectOptionGroup } from '@arco-design/web-vue'; 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 FormMode = 'create' | 'edit';
export type ValueType = 'Array' | 'string'; export type ValueType = 'Array' | 'string';
// 自定义检验器,为了传入动态渲染的表单项下标 // 自定义检验器,为了传入动态渲染的表单项下标
@ -9,7 +9,7 @@ export interface CustomValidator {
} }
export interface FormItemModel { export interface FormItemModel {
filed: string; field: string;
type: FormItemType; type: FormItemType;
rules?: (FieldRule & CustomValidator)[]; rules?: (FieldRule & CustomValidator)[];
label?: string; label?: string;
@ -26,4 +26,5 @@ export interface FormItemModel {
defaultValue?: string | string[] | number | number[] | boolean; // 默认值 defaultValue?: string | string[] | number | number[] | boolean; // 默认值
hasRedStar?: boolean; // 是否有红星 hasRedStar?: boolean; // 是否有红星
tooltip?: string; tooltip?: string;
[key: string]: any;
} }

View File

@ -7,6 +7,6 @@ export default {
'ms.case.associate.version': '版本', 'ms.case.associate.version': '版本',
'ms.case.associate.versionPlaceholder': '默认最新版本', 'ms.case.associate.versionPlaceholder': '默认最新版本',
'ms.case.associate.tags': '标签', 'ms.case.associate.tags': '标签',
'ms.case.associate.searchPlaceholder': '通过 ID名称搜索', 'ms.case.associate.searchPlaceholder': '通过 ID/名称搜索',
'ms.case.associate.associateSuccess': '关联成功', 'ms.case.associate.associateSuccess': '关联成功',
}; };

View File

@ -34,7 +34,6 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { defineModel, ref } from 'vue';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import MsAvatar from '@/components/pure/ms-avatar/index.vue'; import MsAvatar from '@/components/pure/ms-avatar/index.vue';

View File

@ -41,8 +41,6 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { defineModel, ref } from 'vue';
import MsAvatar from '@/components/pure/ms-avatar/index.vue'; import MsAvatar from '@/components/pure/ms-avatar/index.vue';
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue'; import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';

View File

@ -147,8 +147,6 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { defineModel, ref } from 'vue';
import MsButton from '@/components/pure/ms-button/index.vue'; import MsButton from '@/components/pure/ms-button/index.vue';
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue'; import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
import { Language } from '@/components/pure/ms-code-editor/types'; import { Language } from '@/components/pure/ms-code-editor/types';

View File

@ -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 showDetailMenu = ref(false);
const canShowEnterNode = ref(false); const canShowEnterNode = ref(false);
/** /**
@ -360,8 +553,14 @@
* @param node 被激活/点击的节点 * @param node 被激活/点击的节点
*/ */
async function handleNodeSelect(node: MinderJsonNode) { async function handleNodeSelect(node: MinderJsonNode) {
checkNodeCanShowMenu(node);
const { data } = 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 ( if (
data?.resource?.includes(moduleTag) && data?.resource?.includes(moduleTag) &&
(node.children || []).length > 0 && (node.children || []).length > 0 &&
@ -381,84 +580,9 @@
} }
} else if (data?.resource?.includes(moduleTag) && data.count > 0 && data.isLoaded !== true) { } else if (data?.resource?.includes(moduleTag) && data.count > 0 && data.isLoaded !== true) {
// //
try { await initNodeCases(node);
loading.value = true; showDetailMenu.value = false;
showDetailMenu.value = false; extraVisible.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;
}
} else { } else {
// //
extraVisible.value = false; extraVisible.value = false;

View File

@ -35,6 +35,10 @@ export default function useMinderBaseApi({ hasEditPermission }: { hasEditPermiss
function canShowFloatMenu() { function canShowFloatMenu() {
if (window.minder) { if (window.minder) {
const node: MinderJsonNode = window.minder.getSelectedNode(); const node: MinderJsonNode = window.minder.getSelectedNode();
if (node.data?.type === 'tmp') {
// 临时节点不展示浮动菜单
return false;
}
if (!hasEditPermission) { if (!hasEditPermission) {
if (node?.data?.resource?.includes(caseTag)) { if (node?.data?.resource?.includes(caseTag)) {
// 没有编辑权限情况下,用例节点可展示浮动菜单(需要展示详情按钮) // 没有编辑权限情况下,用例节点可展示浮动菜单(需要展示详情按钮)

View File

@ -379,6 +379,7 @@
} }
} }
const inInsertingNode = ref(false);
/** /**
* 执行插入节点 * 执行插入节点
* @param command 插入命令 * @param command 插入命令
@ -447,6 +448,7 @@
}; };
} }
if (child) { if (child) {
inInsertingNode.value = true;
execInert(type, child); execInert(type, child);
nextTick(() => { nextTick(() => {
execInert('AppendChildNode', caseCountNodeData); execInert('AppendChildNode', caseCountNodeData);
@ -454,6 +456,9 @@
// //
execInert('AppendSiblingNode', envNodeData); execInert('AppendSiblingNode', envNodeData);
execInert('AppendSiblingNode', resourcePoolNodeData); execInert('AppendSiblingNode', resourcePoolNodeData);
setTimeout(() => {
inInsertingNode.value = false;
}, 0);
} }
}); });
} }
@ -669,7 +674,10 @@
if (node.data?.level === 3 && node.data?.resource?.[0] === caseCountTag) { if (node.data?.level === 3 && node.data?.resource?.[0] === caseCountTag) {
window.minder.toggleSelect(node); window.minder.toggleSelect(node);
window.minder.selectById(node.parent?.data?.id); window.minder.selectById(node.parent?.data?.id);
associateCase(); if (!inInsertingNode.value && hasEditPermission && hasAnyPermission(['PROJECT_TEST_PLAN:READ+ASSOCIATION'])) {
//
associateCase();
}
} else if ( } else if (
node.data?.level === 3 && node.data?.level === 3 &&
(node.data?.resource?.[0] === resourcePoolTag || node.data?.resource?.[0] === envTag) (node.data?.resource?.[0] === resourcePoolTag || node.data?.resource?.[0] === envTag)

View File

@ -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>

View File

@ -399,6 +399,10 @@
(val) => { (val) => {
if (typeof val === 'boolean') { if (typeof val === 'boolean') {
treeRef.value?.expandAll(val); treeRef.value?.expandAll(val);
filterTreeData.value = mapTree(filterTreeData.value, (node) => {
node.expanded = val;
return node;
});
} }
} }
); );

View File

@ -72,8 +72,6 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { defineModel } from 'vue';
import MsIcon from '@/components/pure/ms-icon-font/index.vue'; import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import MsTag from '../ms-tag/ms-tag.vue'; import MsTag from '../ms-tag/ms-tag.vue';
import FilterForm from './FilterForm.vue'; import FilterForm from './FilterForm.vue';

View File

@ -23,7 +23,6 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { defineModel } from 'vue';
import { Message } from '@arco-design/web-vue'; import { Message } from '@arco-design/web-vue';
import { validateJIRAKey } from '@/api/modules/project-management/menuManagement'; import { validateJIRAKey } from '@/api/modules/project-management/menuManagement';

View File

@ -293,7 +293,6 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, defineModel, nextTick, onMounted, ref, useAttrs, watch } from 'vue';
import { Message } from '@arco-design/web-vue'; import { Message } from '@arco-design/web-vue';
import MsIcon from '@/components/pure/ms-icon-font/index.vue'; import MsIcon from '@/components/pure/ms-icon-font/index.vue';

View File

@ -4,7 +4,9 @@
<template #content> <template #content>
<div class="mb-2 flex items-center justify-between"> <div class="mb-2 flex items-center justify-between">
<div class="font-medium text-[var(--color-text-1)]">{{ t('msTable.columnSetting.display') }}</div> <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> </div>
<template v-if="props.showPagination"> <template v-if="props.showPagination">
<div class="font-medium text-[var(--color-text-4)]">{{ t('msTable.columnSetting.pageSize') }} </div> <div class="font-medium text-[var(--color-text-4)]">{{ t('msTable.columnSetting.pageSize') }} </div>

View File

@ -165,8 +165,8 @@ export default {
'common.resourceDeleted': '资源已被删除', 'common.resourceDeleted': '资源已被删除',
'common.resourceExpired': '链接已失效,请重新获取', 'common.resourceExpired': '链接已失效,请重新获取',
'common.refresh': '刷新', 'common.refresh': '刷新',
'common.searchByIdName': '通过ID 或名称搜索', 'common.searchByIdName': '通过 ID/名称搜索',
'common.searchByIDNameTag': '通过ID、名称或标签搜索', 'common.searchByIDNameTag': '通过 ID/名称/标签搜索',
'common.archive': '归档', 'common.archive': '归档',
'common.running': '执行中', 'common.running': '执行中',
'common.unExecute': '未执行', 'common.unExecute': '未执行',

View File

@ -595,13 +595,13 @@
body-class="!p-0" body-class="!p-0"
:width="480" :width="480"
title-align="start" title-align="start"
:auto-size="{ minRows: 2 }"
@ok="applyQuickInputDesc" @ok="applyQuickInputDesc"
@close="clearQuickInputDesc" @close="clearQuickInputDesc"
> >
<a-textarea <a-textarea
v-model:model-value="quickInputDescValue" v-model:model-value="quickInputDescValue"
:placeholder="t('apiTestDebug.descPlaceholder')" :placeholder="t('apiTestDebug.descPlaceholder')"
:auto-size="{ minRows: 2 }"
:max-length="1000" :max-length="1000"
></a-textarea> ></a-textarea>
</a-modal> </a-modal>

View File

@ -1,7 +1,7 @@
export default { export default {
'apiTestDebug.newApi': '新建请求', 'apiTestDebug.newApi': '新建请求',
'apiTestDebug.importApi': '导入请求', 'apiTestDebug.importApi': '导入请求',
'apiTestDebug.urlPlaceholder': '请输入包含 httphttps 的完整URL', 'apiTestDebug.urlPlaceholder': '请输入包含 http/https 的完整URL',
'apiTestDebug.definitionUrlPlaceholder': '输入接口URL以“/”开始', 'apiTestDebug.definitionUrlPlaceholder': '输入接口URL以“/”开始',
'apiTestDebug.serverExec': '服务端执行', 'apiTestDebug.serverExec': '服务端执行',
'apiTestDebug.localExec': '本地执行', 'apiTestDebug.localExec': '本地执行',

View File

@ -146,7 +146,7 @@ export default {
'apiTestManagement.quoteType': '引用类型', 'apiTestManagement.quoteType': '引用类型',
'apiTestManagement.belongOrg': '所属组织', 'apiTestManagement.belongOrg': '所属组织',
'apiTestManagement.belongProject': '所属项目', 'apiTestManagement.belongProject': '所属项目',
'apiTestManagement.quoteSearchPlaceholder': '输入 ID名称搜索', 'apiTestManagement.quoteSearchPlaceholder': '输入 ID/名称搜索',
'apiTestManagement.click': '点击', 'apiTestManagement.click': '点击',
'apiTestManagement.getResponse': '获取响应内容', 'apiTestManagement.getResponse': '获取响应内容',
'apiTestManagement.tableNoDataAndPlease': '暂无数据,请', 'apiTestManagement.tableNoDataAndPlease': '暂无数据,请',

View File

@ -41,7 +41,7 @@ export default {
'apiScenario.params.csvQuoteAllow': '允许带引号', 'apiScenario.params.csvQuoteAllow': '允许带引号',
'apiScenario.params.csvRecycle': '遇到文件结束符再次循环', 'apiScenario.params.csvRecycle': '遇到文件结束符再次循环',
'apiScenario.params.csvStop': '遇到文件结束符停止线程', 'apiScenario.params.csvStop': '遇到文件结束符停止线程',
'apiScenario.params.searchPlaceholder': '通过名称标签搜索', 'apiScenario.params.searchPlaceholder': '通过名称/标签搜索',
'apiScenario.params.priority': 'apiScenario.params.priority':
'变量优先级:临时参数>场景参数 >环境参数>全局参数;注: 避免使用同名变量,同名变量时场景级 CSV 优先级最高', '变量优先级:临时参数>场景参数 >环境参数>全局参数;注: 避免使用同名变量,同名变量时场景级 CSV 优先级最高',
'apiScenario.params.name': '变量名称', 'apiScenario.params.name': '变量名称',

View File

@ -168,7 +168,6 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { defineModel, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { useClipboard } from '@vueuse/core'; import { useClipboard } from '@vueuse/core';
import { Message } from '@arco-design/web-vue'; import { Message } from '@arco-design/web-vue';

View File

@ -119,7 +119,7 @@ export default {
permanentlyDeleteTip: '是否彻底删除 {name} 缺陷?', permanentlyDeleteTip: '是否彻底删除 {name} 缺陷?',
deleteContent: '删除后,缺陷无法恢复,请谨慎操作!', deleteContent: '删除后,缺陷无法恢复,请谨慎操作!',
batchDelete: '是否彻底删除{count}条缺陷?', batchDelete: '是否彻底删除{count}条缺陷?',
searchPlaceholder: '通过 ID名称搜索', searchPlaceholder: '通过 ID/名称搜索',
deleteTime: '删除时间', deleteTime: '删除时间',
deleteMan: '删除人', deleteMan: '删除人',
}, },

View File

@ -13,8 +13,8 @@ export default {
'caseManagement.featureCase.rename': '重命名', 'caseManagement.featureCase.rename': '重命名',
'caseManagement.featureCase.recycle': '回收站', 'caseManagement.featureCase.recycle': '回收站',
'caseManagement.featureCase.versionPlaceholder': '默认为最新版本', 'caseManagement.featureCase.versionPlaceholder': '默认为最新版本',
'caseManagement.featureCase.searchByNameAndId': '通过ID、名称或标签搜索', 'caseManagement.featureCase.searchByNameAndId': '通过 ID/名称/标签搜索',
'caseManagement.featureCase.searchByIdAndName': '通过ID 或名称搜索', 'caseManagement.featureCase.searchByIdAndName': '通过 ID/名称搜索',
'caseManagement.featureCase.searchByName': '通过名称搜索', 'caseManagement.featureCase.searchByName': '通过名称搜索',
'caseManagement.featureCase.filter': '筛选', 'caseManagement.featureCase.filter': '筛选',
'caseManagement.featureCase.setFilterCondition': '设置筛选条件', 'caseManagement.featureCase.setFilterCondition': '设置筛选条件',

View File

@ -2,8 +2,8 @@ export default {
'caseManagement.caseReview.create': '创建评审', 'caseManagement.caseReview.create': '创建评审',
'caseManagement.caseReview.waitMyReview': '我评审的', 'caseManagement.caseReview.waitMyReview': '我评审的',
'caseManagement.caseReview.myCreate': '我创建的', 'caseManagement.caseReview.myCreate': '我创建的',
'caseManagement.caseReview.searchPlaceholder': '通过 ID名称搜索', 'caseManagement.caseReview.searchPlaceholder': '通过 ID/名称搜索',
'caseManagement.caseReview.list.searchPlaceholder': '通过ID、名称或标签搜索', 'caseManagement.caseReview.list.searchPlaceholder': '通过 ID/名称/标签搜索',
'caseManagement.caseReview.archive': '归档', 'caseManagement.caseReview.archive': '归档',
'caseManagement.caseReview.tableNoData': '暂无数据,请', 'caseManagement.caseReview.tableNoData': '暂无数据,请',
'caseManagement.caseReview.tableNoDataNoPermission': '暂无数据', 'caseManagement.caseReview.tableNoDataNoPermission': '暂无数据',

View File

@ -44,7 +44,7 @@ export default {
'project.commonScript.commonScriptList': '公共脚本列表', 'project.commonScript.commonScriptList': '公共脚本列表',
'project.commonScript.folderSearchPlaceholder': '请输入模块名称', 'project.commonScript.folderSearchPlaceholder': '请输入模块名称',
'project.commonScript.allApis': '全部接口', 'project.commonScript.allApis': '全部接口',
'project.commonScript.searchPlaceholder': '通过 ID名称搜索', 'project.commonScript.searchPlaceholder': '通过 ID/名称搜索',
'project.commonScript.noTreeData': '暂无接口数据', 'project.commonScript.noTreeData': '暂无接口数据',
'project.commonScript.apiName': '接口名称', 'project.commonScript.apiName': '接口名称',
'project.commonScript.requestType': '请求类型', 'project.commonScript.requestType': '请求类型',

View File

@ -67,7 +67,6 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { defineModel, ref } from 'vue';
import { type FileItem, Message } from '@arco-design/web-vue'; import { type FileItem, Message } from '@arco-design/web-vue';
import MsUpload from '@/components/pure/ms-upload/index.vue'; import MsUpload from '@/components/pure/ms-upload/index.vue';

View File

@ -42,7 +42,6 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { defineModel, onBeforeMount, ref } from 'vue';
import { VueDraggable } from 'vue-draggable-plus'; import { VueDraggable } from 'vue-draggable-plus';
import MsButton from '@/components/pure/ms-button/index.vue'; import MsButton from '@/components/pure/ms-button/index.vue';

View File

@ -74,7 +74,7 @@
type UserModalMode = 'create' | 'edit'; type UserModalMode = 'create' | 'edit';
const batchFormModels: Ref<FormItemModel[]> = ref([ const batchFormModels: Ref<FormItemModel[]> = ref([
{ {
filed: 'ip', field: 'ip',
type: 'input', type: 'input',
label: 'project.environmental.host.ip', label: 'project.environmental.host.ip',
placeholder: 'project.environmental.host.ipPlaceholder', placeholder: 'project.environmental.host.ipPlaceholder',
@ -84,14 +84,14 @@
], ],
}, },
{ {
filed: 'domain', field: 'domain',
type: 'input', type: 'input',
label: 'project.environmental.host.hostName', label: 'project.environmental.host.hostName',
placeholder: 'project.environmental.host.hostNamePlaceholder', placeholder: 'project.environmental.host.hostNamePlaceholder',
rules: [{ required: true, message: t('project.environmental.host.hostNameIsRequire') }], rules: [{ required: true, message: t('project.environmental.host.hostNameIsRequire') }],
}, },
{ {
filed: 'description', field: 'description',
type: 'input', type: 'input',
label: 'common.desc', label: 'common.desc',
placeholder: 'project.environmental.host.descPlaceholder', placeholder: 'project.environmental.host.descPlaceholder',

View File

@ -224,12 +224,9 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { defineModel } from 'vue';
import { Message, ValidatedError } from '@arco-design/web-vue'; import { Message, ValidatedError } from '@arco-design/web-vue';
import MsDrawer from '@/components/pure/ms-drawer/index.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 { getEnvModules } from '@/api/modules/api-test/management';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';

View File

@ -15,7 +15,7 @@ export default {
'project.environmental.supportFormat': '仅支持MeterSphere导出的Json文件单个大小不超过 50M', 'project.environmental.supportFormat': '仅支持MeterSphere导出的Json文件单个大小不超过 50M',
'project.environmental.importTile': '注意!导入后会覆盖原全局参数', 'project.environmental.importTile': '注意!导入后会覆盖原全局参数',
'project.environmental.mustContain': '必含', 'project.environmental.mustContain': '必含',
'project.environmental.searchParamsHolder': '通过名称标签搜索', 'project.environmental.searchParamsHolder': '通过名称/标签搜索',
'project.environmental.paramName': '参数名称', 'project.environmental.paramName': '参数名称',
'project.environmental.paramNamePlaceholder': '请输入参数名称', 'project.environmental.paramNamePlaceholder': '请输入参数名称',
'project.environmental.paramType': '类型', 'project.environmental.paramType': '类型',

View File

@ -6,9 +6,9 @@
</div> </div>
</div> </div>
<div class="mb-4 flex items-center justify-between"> <div class="mb-4 flex items-center justify-between">
<a-button v-permission="['PROJECT_APPLICATION_API:UPDATE']" type="primary" @click="showAddRule(undefined)">{{ <a-button v-permission="['PROJECT_APPLICATION_API:UPDATE']" type="primary" @click="showAddRule(undefined)">
t('project.menu.addFalseAlertRules') {{ t('project.menu.addFalseAlertRules') }}
}}</a-button> </a-button>
<a-input-search <a-input-search
v-model="keyword" v-model="keyword"
:placeholder="t('project.menu.nameSearch')" :placeholder="t('project.menu.nameSearch')"
@ -29,9 +29,9 @@
<template v-if="!record.enable"> <template v-if="!record.enable">
<div class="flex flex-row"> <div class="flex flex-row">
<span v-permission="['PROJECT_APPLICATION_API:UPDATE']" class="flex flex-row"> <span v-permission="['PROJECT_APPLICATION_API:UPDATE']" class="flex flex-row">
<MsButton class="!mr-0" @click="handleEnableOrDisableProject(record.id)">{{ <MsButton class="!mr-0" @click="handleEnableOrDisableProject(record.id)">
t('common.enable') {{ t('common.enable') }}
}}</MsButton> </MsButton>
<a-divider direction="vertical" /> <a-divider direction="vertical" />
</span> </span>
<span> <span>
@ -50,9 +50,9 @@
<a-divider class="h-[16px]" direction="vertical" /> <a-divider class="h-[16px]" direction="vertical" />
</span> </span>
<span v-permission="['PROJECT_APPLICATION_API:UPDATE']" class="flex flex-row items-center"> <span v-permission="['PROJECT_APPLICATION_API:UPDATE']" class="flex flex-row items-center">
<MsButton class="!mr-0" @click="handleEnableOrDisableProject(record.id, false)">{{ <MsButton class="!mr-0" @click="handleEnableOrDisableProject(record.id, false)">
t('common.disable') {{ t('common.disable') }}
}}</MsButton> </MsButton>
<a-divider class="h-[16px]" direction="vertical" /> <a-divider class="h-[16px]" direction="vertical" />
</span> </span>
<MsTableMoreAction <MsTableMoreAction
@ -174,7 +174,7 @@
}; };
const initBatchFormModels: FormItemModel[] = [ const initBatchFormModels: FormItemModel[] = [
{ {
filed: 'name', field: 'name',
type: 'input', type: 'input',
label: 'project.menu.rule.ruleName', label: 'project.menu.rule.ruleName',
rules: [ rules: [
@ -183,34 +183,35 @@
], ],
}, },
{ {
filed: 'type', field: 'type',
type: 'tagInput', type: 'tagInput',
label: 'project.menu.rule.label', label: 'project.menu.rule.label',
}, },
{ {
filed: 'rule', field: 'rule',
type: 'multiple', type: 'multiple',
label: 'project.menu.rule.rule', label: 'project.menu.rule.rule',
hasRedStar: true, hasRedStar: true,
children: [ children: [
{ {
filed: 'respType', // -/header/data/body field: 'respType', // -/header/data/body
type: 'select', type: 'select',
options: headerOptions.value, options: headerOptions.value,
className: 'w-[205px]', className: 'w-[205px]',
defaultValue: 'RESPONSE_HEADERS', defaultValue: 'RESPONSE_HEADERS',
}, },
{ {
filed: 'relation', // - field: 'relation', // -
type: 'select', type: 'select',
options: relationOptions.value, options: relationOptions.value,
defaultValue: 'CONTAINS', defaultValue: 'CONTAINS',
className: 'w-[120px]', className: 'w-[120px]',
}, },
{ {
filed: 'expression', // - field: 'expression', // -
type: 'input', type: 'textarea',
rules: [{ required: true, message: t('project.menu.rule.expressionNotNull') }], rules: [{ required: true, message: t('project.menu.rule.expressionNotNull') }],
title: t('project.menu.rule.ruleExpression'),
className: 'w-[301px]', className: 'w-[301px]',
}, },
], ],
@ -410,7 +411,7 @@
addVisible.value = true; addVisible.value = true;
}; };
const handleCancel = (shouldSearch: boolean, isClose = true) => { const handleCancel = (shouldSearch: boolean) => {
if (shouldSearch) { if (shouldSearch) {
fetchData(); fetchData();
} }
@ -441,7 +442,7 @@
Message.success(t('common.updateSuccess')); Message.success(t('common.updateSuccess'));
} }
handleCancel(true, false); handleCancel(true);
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(error); console.log(error);

View File

@ -1,10 +1,10 @@
export default { export default {
'project.menu.management': 'Application Setting', 'project.menu.management': 'Application Settings',
'project.menu.manageTip': '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.name': 'Menu Name',
'project.menu.pleaseConfig': 'Please Configure', 'project.menu.pleaseConfig': 'Please configure',
'project.menu.count': 'Items', 'project.menu.count': 'Count',
'project.menu.WORKSTATION_SYNC_RULE': 'Interface Test Update Synchronization Rule', 'project.menu.WORKSTATION_SYNC_RULE': 'Interface Test Update Synchronization Rule',
'project.menu.TEST_PLAN_CLEAN_REPORT': 'Report Retention Time Range', '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_CLEAN_REPORT': 'Report Retention Time Range',
'project.menu.UI_SHARE_REPORT': 'Report Link Validity Period', 'project.menu.UI_SHARE_REPORT': 'Report Link Validity Period',
'project.menu.UI_RESOURCE_POOL': 'Execution Resource Pool', '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_CLEAN_REPORT': 'Report Retention Time Range',
'project.menu.PERFORMANCE_TEST_SHARE_REPORT': 'Report Link Validity Period', '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': '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', 'Specify a user to review script steps in interface test cases; you can change the reviewer',
'project.menu.API_URL_REPEATABLE': 'Interface API URL Can Be Repeated', 'project.menu.API_URL_REPEATABLE': 'API Definition URL Repeatability',
'project.menu.API_CLEAN_REPORT': 'Report Retention Time Range', 'project.menu.API_CLEAN_REPORT': 'Report Retention Time Range',
'project.menu.API_SHARE_REPORT': 'Report Link Validity Period', 'project.menu.API_SHARE_REPORT': 'Report Link Validity Period',
'project.menu.API_RESOURCE_POOL': 'Execution Resource Pool', 'project.menu.API_RESOURCE_POOL': 'Execution Resource Pool',
'project.menu.API_RESOURCE_POOL_TIP': 'Execution machine for interface testing', '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': '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', 'Specify a user to review script steps in interface test cases; you can change the reviewer',
'project.menu.API_ERROR_REPORT_RULE': 'Fake Error Rule', 'project.menu.API_ERROR_REPORT_RULE': 'False Alert Rule',
'project.menu.API_ERROR_REPORT_RULE_TIP': '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', '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 Sync CASE', 'project.menu.API_SYNC_CASE': 'Change Synchronized CASE',
'project.menu.CASE_PUBLIC': 'Public Case Library', 'project.menu.CASE_PUBLIC': 'Public Test Case Library',
'project.menu.CASE_RE_REVIEW': 'Resubmit for Review', 'project.menu.CASE_RE_REVIEW': 'Re-review',
'project.menu.CASE_RELATED': 'Related Requirements', '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.SYNC_ENABLE': 'Status',
'project.menu.MECHANISM': 'Interface Test Update Synchronization Rule', '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.row1': 'The system displays data that meets the 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.row2': 'Synchronize defects created on the platform to third-party project management platforms',
'project.menu.row3': 'You can add cases to the public case library for shared use', 'project.menu.row3': 'Add test cases to the public test case library for sharing',
'project.menu.row4': 'You can associate cases with third-party project management platforms', 'project.menu.row4': 'Associate test cases with third-party project management platforms',
'project.menu.row5': 'project.menu.row5':
'When the case changes during the review activity, the case status automatically switches to resubmit for review', 'When changes occur in test cases during the review process, the test case status automatically switches to re-review',
'project.menu.row6': 'After turning on, the interface definition module repetitiveness check will not check the URL', 'project.menu.row6': 'When enabled, the interface definition module will not validate URL duplication',
'project.menu.row7': 'When the interface definition changes, the interface CASE is automatically synchronized', 'project.menu.row7': 'Automatically synchronize interface CASE when the interface definition changes',
'project.menu.notConfig': 'Third-party information is not configured, click', 'project.menu.notConfig': 'Third-party information not configured, click',
'project.menu.configure': 'to configure', 'project.menu.configure': 'to configure',
'project.menu.status': 'Status', 'project.menu.status': 'Status',
'project.menu.incrementalSync': 'Incremental Sync', 'project.menu.incrementalSync': 'Incremental Synchronization',
'project.menu.incrementalSyncTip': 'Only the contents of the three-party bug existing in MS are changed', 'project.menu.incrementalSyncTip': 'Only make content changes to existing third-party defects in MS',
'project.menu.fullSync': 'Full Sync', 'project.menu.fullSync': 'Full Synchronization',
'project.menu.fullSyncTip': 'Fully sync bug of third-party platforms to MS', 'project.menu.fullSyncTip': 'Fully synchronize defects from third-party platforms to MS',
'project.menu.platformPlaceholder': '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.platformLabel': 'Third-party Project Management Platform',
'project.menu.syncMechanism': 'Sync Mechanism', 'project.menu.syncMechanism': 'Synchronization Mechanism',
'project.menu.CRON_EXPRESSION': 'Sync Frequency', 'project.menu.CRON_EXPRESSION': 'Synchronization Frequency',
'project.menu.projectKey': 'Project Key', 'project.menu.projectKey': 'Project Key',
'project.menu.projectId': 'Project ID', 'project.menu.projectId': 'Project ID',
'project.menu.organizationId': 'Organization ID', 'project.menu.organizationId': 'Organization ID',
'project.menu.azureId': 'Azure Filter ID', 'project.menu.azureId': 'Azure Filter ID',
'project.menu.defectType': 'Defect Type', 'project.menu.defectType': 'Defect Type',
'project.menu.demandType': 'Demand Type', 'project.menu.demandType': 'Requirement Type',
'project.menu.howGetJiraKey': 'How to get JIRA project key', 'project.menu.howGetJiraKey': 'How to Get JIRA Project Key',
'project.menu.preview': 'Preview', 'project.menu.preview': 'Preview',
'project.menu.pleaseInputJiraKey': 'Please enter JIRA project key', 'project.menu.pleaseInputJiraKey': 'Please enter JIRA project key',
'project.menu.addFalseAlertRules': 'Add False Alert Rules', 'project.menu.addFalseAlertRules': 'Add False Alert Rule',
'project.menu.updateFalseAlertRules': 'update False Alert Rules', 'project.menu.updateFalseAlertRules': 'Update False Alert Rule',
'project.menu.nameSearch': 'Search by Name', 'project.menu.nameSearch': 'Search by Name',
// Sync defects // Defect Synchronization
'project.menu.defect.enableTip': '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': 'project.menu.defect.closeTip':
'Turn off: The defects created by the platform cannot be synced to the third-party project management platform', 'Disable: Defects created on the platform will not be synchronized to third-party project management platforms',
'project.menu.demand.enableTip': 'On: functional cases can relate to third-party demands', 'project.menu.demand.enableTip':
'project.menu.demand.closeTip': 'Off: functional cases cannot relate to third party demands', '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.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!',
}; };

View File

@ -80,6 +80,7 @@ export default {
'project.menu.rule.updateTime': '更新时间', 'project.menu.rule.updateTime': '更新时间',
'project.menu.rule.operation': '操作', 'project.menu.rule.operation': '操作',
'project.menu.rule.ruleName': '规则名称', 'project.menu.rule.ruleName': '规则名称',
'project.menu.rule.ruleExpression': '限制条件',
'project.menu.rule.ruleNameNotNull': '规则名称不能为空', 'project.menu.rule.ruleNameNotNull': '规则名称不能为空',
'project.menu.rule.ruleNameRepeat': '名称重复请修改', 'project.menu.rule.ruleNameRepeat': '名称重复请修改',
'project.menu.rule.expressionNotNull': '限制条件不能为空', 'project.menu.rule.expressionNotNull': '限制条件不能为空',

View File

@ -15,7 +15,7 @@ export default {
'project.projectVersion.publishTime': '发布时间', 'project.projectVersion.publishTime': '发布时间',
'project.projectVersion.createTime': '创建时间', 'project.projectVersion.createTime': '创建时间',
'project.projectVersion.creator': '创建人', 'project.projectVersion.creator': '创建人',
'project.projectVersion.searchPlaceholder': '通过ID/名称搜索', 'project.projectVersion.searchPlaceholder': '通过 ID/名称搜索',
'project.projectVersion.quickCreate': '快速创建版本', 'project.projectVersion.quickCreate': '快速创建版本',
'project.projectVersion.versionNamePlaceholder': '请输入版本名称', 'project.projectVersion.versionNamePlaceholder': '请输入版本名称',
'project.projectVersion.versionNameRequired': '版本名称不能为空', 'project.projectVersion.versionNameRequired': '版本名称不能为空',

View File

@ -212,7 +212,7 @@
// -1. // -1.
const onlyOptions: Ref<FormItemModel> = ref({ const onlyOptions: Ref<FormItemModel> = ref({
filed: 'text', field: 'text',
type: 'input', type: 'input',
label: '', label: '',
rules: [ rules: [
@ -227,7 +227,7 @@
// -2 // -2
const bugBatchFormRules = ref<FormItemModel[]>([ const bugBatchFormRules = ref<FormItemModel[]>([
{ {
filed: 'text', field: 'text',
type: 'input', type: 'input',
label: '', label: '',
rules: [ rules: [
@ -239,7 +239,7 @@
hideLabel: true, hideLabel: true,
}, },
{ {
filed: 'value', field: 'value',
type: 'input', type: 'input',
label: '', label: '',
rules: [ rules: [

View File

@ -50,7 +50,7 @@ export default {
'system.organization.updateOrganizationSuccess': '更新组织成功', 'system.organization.updateOrganizationSuccess': '更新组织成功',
'system.organization.createProject': '创建项目', 'system.organization.createProject': '创建项目',
'system.organization.subordinateOrg': '所属组织', 'system.organization.subordinateOrg': '所属组织',
'system.organization.searchIndexPlaceholder': '通过ID/名称搜索', 'system.organization.searchIndexPlaceholder': '通过 ID/名称搜索',
'system.organization.searchUserPlaceholder': '通过名称/邮箱/手机搜索', 'system.organization.searchUserPlaceholder': '通过名称/邮箱/手机搜索',
'system.organization.organizationAdminRequired': '组织管理员不能为空', 'system.organization.organizationAdminRequired': '组织管理员不能为空',
'system.project.enableTitle': '启用项目', 'system.project.enableTitle': '启用项目',
@ -73,7 +73,7 @@ export default {
'system.organization.projectIsDisabled': '项目已结束,可在 项目列表 启用', 'system.organization.projectIsDisabled': '项目已结束,可在 项目列表 启用',
'system.project.deleteName': '确认删除 {name} 这个项目吗?', 'system.project.deleteName': '确认删除 {name} 这个项目吗?',
'system.project.deleteTip': '删除后,系统会在 30天 后执行删除项目 (含项目下所有业务数据),请谨慎操作!', 'system.project.deleteTip': '删除后,系统会在 30天 后执行删除项目 (含项目下所有业务数据),请谨慎操作!',
'system.project.searchPlaceholder': '通过ID或项目名称搜索', 'system.project.searchPlaceholder': '通过 ID/项目名称搜索',
'system.project.afterModule': '取消模块后用户将无法进入指定模块,已存在的数据会继续保留', 'system.project.afterModule': '取消模块后用户将无法进入指定模块,已存在的数据会继续保留',
'system.project.projectAdminIsNotNull': '项目管理员不能为空', 'system.project.projectAdminIsNotNull': '项目管理员不能为空',
'system.project.pleaseSelectAdmin': '请选择项目管理员', 'system.project.pleaseSelectAdmin': '请选择项目管理员',

View File

@ -574,21 +574,21 @@
const batchFormRef = ref<InstanceType<typeof MsBatchForm>>(); const batchFormRef = ref<InstanceType<typeof MsBatchForm>>();
const batchFormModels: Ref<FormItemModel[]> = ref([ const batchFormModels: Ref<FormItemModel[]> = ref([
{ {
filed: 'ip', field: 'ip',
type: 'input', type: 'input',
label: 'system.resourcePool.ip', label: 'system.resourcePool.ip',
rules: [{ required: true, message: t('system.resourcePool.ipRequired') }], rules: [{ required: true, message: t('system.resourcePool.ipRequired') }],
placeholder: 'system.resourcePool.ipPlaceholder', placeholder: 'system.resourcePool.ipPlaceholder',
}, },
{ {
filed: 'port', field: 'port',
type: 'input', type: 'input',
label: 'system.resourcePool.port', label: 'system.resourcePool.port',
rules: [{ required: true, message: t('system.resourcePool.portRequired') }], rules: [{ required: true, message: t('system.resourcePool.portRequired') }],
placeholder: 'system.resourcePool.portPlaceholder', placeholder: 'system.resourcePool.portPlaceholder',
}, },
{ {
filed: 'concurrentNumber', field: 'concurrentNumber',
type: 'inputNumber', type: 'inputNumber',
label: 'system.resourcePool.concurrentNumber', label: 'system.resourcePool.concurrentNumber',
rules: [ rules: [

View File

@ -834,14 +834,14 @@
const batchFormRef = ref<InstanceType<typeof MsBatchForm>>(); const batchFormRef = ref<InstanceType<typeof MsBatchForm>>();
const batchFormModels: Ref<FormItemModel[]> = ref([ const batchFormModels: Ref<FormItemModel[]> = ref([
{ {
filed: 'name', field: 'name',
type: 'input', type: 'input',
label: 'system.user.createUserName', label: 'system.user.createUserName',
rules: [{ required: true, message: t('system.user.createUserNameNotNull') }, { validator: checkUerName }], rules: [{ required: true, message: t('system.user.createUserNameNotNull') }, { validator: checkUerName }],
placeholder: 'system.user.createUserNamePlaceholder', placeholder: 'system.user.createUserNamePlaceholder',
}, },
{ {
filed: 'email', field: 'email',
type: 'input', type: 'input',
label: 'system.user.createUserEmail', label: 'system.user.createUserEmail',
rules: [ rules: [
@ -852,7 +852,7 @@
placeholder: 'system.user.createUserEmailPlaceholder', placeholder: 'system.user.createUserEmailPlaceholder',
}, },
{ {
filed: 'phone', field: 'phone',
type: 'input', type: 'input',
label: 'system.user.createUserPhone', label: 'system.user.createUserPhone',
rules: [{ validator: checkUerPhone }], rules: [{ validator: checkUerPhone }],

View File

@ -37,7 +37,7 @@ export default {
pleaseInputUserGroupName: '请输入用户组名称,且不与其他用户组名称重复', pleaseInputUserGroupName: '请输入用户组名称,且不与其他用户组名称重复',
userGroupNameIsExist: `已有 {name} ,请更改`, userGroupNameIsExist: `已有 {name} ,请更改`,
pleaseSelectAuthScope: '请选择用户组所属的权限范围', pleaseSelectAuthScope: '请选择用户组所属的权限范围',
searchPlaceholder: '通过ID/名称搜索', searchPlaceholder: '通过 ID/名称搜索',
SYSTEM: '系统', SYSTEM: '系统',
PROJECT: '项目', PROJECT: '项目',
ORGANIZATION: '组织', ORGANIZATION: '组织',

View File

@ -111,7 +111,7 @@ export default {
'testPlan.featureCase.richTextDblclickPlaceholder': '双击可全屏输入', 'testPlan.featureCase.richTextDblclickPlaceholder': '双击可全屏输入',
'testPlan.featureCase.autoNextTip1': '开启:提交结果后,跳转至下一条用例', 'testPlan.featureCase.autoNextTip1': '开启:提交结果后,跳转至下一条用例',
'testPlan.featureCase.autoNextTip2': '关闭:提交结果后,还在当前', 'testPlan.featureCase.autoNextTip2': '关闭:提交结果后,还在当前',
'testPlan.api.testSetRequired': '测试不能为空', 'testPlan.api.testSetRequired': '测试不能为空',
'testPlan.executeHistory.executionStartAndEndTime': '执行起止时间', 'testPlan.executeHistory.executionStartAndEndTime': '执行起止时间',
'testPlan.executeHistory.testPlanHasTimedOut': '测试计划已超时', 'testPlan.executeHistory.testPlanHasTimedOut': '测试计划已超时',
'testPlan.testPlanGroup.seeArchived': '只看已归档', 'testPlan.testPlanGroup.seeArchived': '只看已归档',
@ -134,6 +134,6 @@ export default {
'testPlan.testPlanGroup.enableScheduleTaskSuccess': '开启定时任务成功', 'testPlan.testPlanGroup.enableScheduleTaskSuccess': '开启定时任务成功',
'testPlan.testPlanGroup.closeScheduleTaskSuccess': '关闭定时任务成功', 'testPlan.testPlanGroup.closeScheduleTaskSuccess': '关闭定时任务成功',
'testPlan.plan': '测试规划', 'testPlan.plan': '测试规划',
'testPlan.planTip': '1.创建测试集进行业务分类测试2.选择测试集关联用例', 'testPlan.planTip': '1.创建测试点进行业务分类测试2.选择测试点关联用例',
'testPlan.planStartToEndTimeTip': '测试计划已超时', 'testPlan.planStartToEndTimeTip': '测试计划已超时',
}; };