fix: 部分缺陷修复
This commit is contained in:
parent
9deabde693
commit
6de3b98fce
|
@ -419,14 +419,9 @@
|
||||||
.arco-checkbox-icon {
|
.arco-checkbox-icon {
|
||||||
border: 1px solid var(--color-text-input-border);
|
border: 1px solid var(--color-text-input-border);
|
||||||
}
|
}
|
||||||
&:hover {
|
|
||||||
.arco-checkbox-icon-hover::before {
|
|
||||||
background-color: rgb(var(--primary-9)) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.arco-checkbox-icon-hover {
|
.arco-checkbox-icon-hover {
|
||||||
&:hover::before {
|
&:hover::before {
|
||||||
background-color: rgb(var(--primary-9)) !important;
|
@apply hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
@change="emit('change')"
|
@change="emit('change')"
|
||||||
/>
|
/>
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-if="model.type === 'inputNumber'"
|
v-else-if="model.type === 'inputNumber'"
|
||||||
v-model:model-value="element[model.filed]"
|
v-model:model-value="element[model.filed]"
|
||||||
class="flex-1"
|
class="flex-1"
|
||||||
:placeholder="t(model.placeholder || '')"
|
:placeholder="t(model.placeholder || '')"
|
||||||
|
@ -73,7 +73,7 @@
|
||||||
@change="emit('change')"
|
@change="emit('change')"
|
||||||
/>
|
/>
|
||||||
<MsTagsInput
|
<MsTagsInput
|
||||||
v-if="model.type === 'tagInput'"
|
v-else-if="model.type === 'tagInput'"
|
||||||
v-model:model-value="element[model.filed]"
|
v-model:model-value="element[model.filed]"
|
||||||
class="flex-1"
|
class="flex-1"
|
||||||
:placeholder="t(model.placeholder || 'common.tagPlaceholder')"
|
:placeholder="t(model.placeholder || 'common.tagPlaceholder')"
|
||||||
|
@ -84,7 +84,7 @@
|
||||||
@change="emit('change')"
|
@change="emit('change')"
|
||||||
/>
|
/>
|
||||||
<a-select
|
<a-select
|
||||||
v-if="model.type === 'select'"
|
v-else-if="model.type === 'select'"
|
||||||
v-model="element[model.filed]"
|
v-model="element[model.filed]"
|
||||||
class="flex-1"
|
class="flex-1"
|
||||||
:placeholder="t(model.placeholder || '')"
|
:placeholder="t(model.placeholder || '')"
|
||||||
|
@ -92,7 +92,7 @@
|
||||||
:field-names="model.filedNames"
|
:field-names="model.filedNames"
|
||||||
@change="emit('change')"
|
@change="emit('change')"
|
||||||
/>
|
/>
|
||||||
<div v-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.filed}${childIndex}${index}`"
|
||||||
|
@ -114,7 +114,7 @@
|
||||||
@change="emit('change')"
|
@change="emit('change')"
|
||||||
/>
|
/>
|
||||||
<a-select
|
<a-select
|
||||||
v-if="child.type === 'select'"
|
v-else-if="child.type === 'select'"
|
||||||
v-model="element[child.filed]"
|
v-model="element[child.filed]"
|
||||||
:class="child.className"
|
:class="child.className"
|
||||||
:placeholder="t(child.placeholder || '')"
|
:placeholder="t(child.placeholder || '')"
|
||||||
|
|
|
@ -26,22 +26,3 @@ export interface FormItemModel {
|
||||||
defaultValue?: string | string[] | number | number[] | boolean; // 默认值
|
defaultValue?: string | string[] | number | number[] | boolean; // 默认值
|
||||||
hasRedStar?: boolean; // 是否有红星
|
hasRedStar?: boolean; // 是否有红星
|
||||||
}
|
}
|
||||||
|
|
||||||
declare const _default: import('vue').DefineComponent<
|
|
||||||
{
|
|
||||||
models: FormItemModel[];
|
|
||||||
formMode: FormMode;
|
|
||||||
addText: string;
|
|
||||||
maxHeight?: string;
|
|
||||||
defaultVals?: Record<string, string[] | string>; // 当外层是编辑状态时,可传入已填充的数据
|
|
||||||
},
|
|
||||||
unknown,
|
|
||||||
import('vue').ComponentOptionsMixin,
|
|
||||||
import('vue').ComponentOptionsMixin,
|
|
||||||
{
|
|
||||||
formValidate: (cb: (res?: Record<string, any>) => void, isSubmit = true) => void;
|
|
||||||
getFormResult: <T>() => T[];
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
|
|
||||||
export declare type MsBatchFormInstance = InstanceType<typeof _default>;
|
|
||||||
|
|
|
@ -113,7 +113,7 @@
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
<template #caseLevel="{ record }">
|
<template #caseLevel="{ record }">
|
||||||
<span>{{ t(record.priority) }}</span>
|
<caseLevel :case-level="getCaseLevel(record)" />
|
||||||
</template>
|
</template>
|
||||||
</ms-base-table>
|
</ms-base-table>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
|
@ -168,6 +168,7 @@
|
||||||
import type { CommonList, ModuleTreeNode, TableQueryParams } from '@/models/common';
|
import type { CommonList, ModuleTreeNode, TableQueryParams } from '@/models/common';
|
||||||
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
|
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
|
||||||
|
|
||||||
|
import type { CaseLevel } from './types';
|
||||||
import { initGetModuleCountFunc, type RequestModuleEnum } from './utils';
|
import { initGetModuleCountFunc, type RequestModuleEnum } from './utils';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -328,7 +329,8 @@
|
||||||
sortDirections: ['ascend', 'descend'],
|
sortDirections: ['ascend', 'descend'],
|
||||||
sorter: true,
|
sorter: true,
|
||||||
},
|
},
|
||||||
width: 200,
|
width: 150,
|
||||||
|
fixed: 'left',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'ms.case.associate.caseName',
|
title: 'ms.case.associate.caseName',
|
||||||
|
@ -338,7 +340,7 @@
|
||||||
sorter: true,
|
sorter: true,
|
||||||
},
|
},
|
||||||
showTooltip: true,
|
showTooltip: true,
|
||||||
width: 300,
|
width: 250,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'ms.case.associate.caseLevel',
|
title: 'ms.case.associate.caseLevel',
|
||||||
|
@ -357,6 +359,7 @@
|
||||||
props.getTableFunc,
|
props.getTableFunc,
|
||||||
{
|
{
|
||||||
columns,
|
columns,
|
||||||
|
scroll: { x: '100%' },
|
||||||
showSetting: false,
|
showSetting: false,
|
||||||
selectable: true,
|
selectable: true,
|
||||||
showSelectAll: true,
|
showSelectAll: true,
|
||||||
|
@ -375,6 +378,11 @@
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 用例等级
|
||||||
|
function getCaseLevel(record: CaseManagementTable) {
|
||||||
|
return (record.customFields.find((item: any) => item.name === '用例等级')?.value as CaseLevel) || 'P1';
|
||||||
|
}
|
||||||
|
|
||||||
const searchParams = ref<TableQueryParams>({
|
const searchParams = ref<TableQueryParams>({
|
||||||
moduleIds: [],
|
moduleIds: [],
|
||||||
version: version.value,
|
version: version.value,
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
import { FormInstance, Message } from '@arco-design/web-vue';
|
import { FormInstance, Message } from '@arco-design/web-vue';
|
||||||
|
|
||||||
import MsPasswordInput from '@/components/pure/ms-password-input/index.vue';
|
import MsPasswordInput from '@/components/pure/ms-password-input/index.vue';
|
||||||
|
@ -39,13 +40,12 @@
|
||||||
|
|
||||||
import { updatePsw } from '@/api/modules/user';
|
import { updatePsw } from '@/api/modules/user';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useUser from '@/hooks/useUser';
|
|
||||||
import useUserStore from '@/store/modules/user';
|
import useUserStore from '@/store/modules/user';
|
||||||
import { encrypted } from '@/utils';
|
import { encrypted } from '@/utils';
|
||||||
import { validatePasswordLength, validateWordPassword } from '@/utils/validate';
|
import { validatePasswordLength, validateWordPassword } from '@/utils/validate';
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const { logout } = useUser();
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const form = ref({
|
const form = ref({
|
||||||
|
@ -111,7 +111,13 @@
|
||||||
}, 1000);
|
}, 1000);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
logout();
|
router.push({
|
||||||
|
name: 'login',
|
||||||
|
query: {
|
||||||
|
...router.currentRoute.value.query,
|
||||||
|
redirect: router.currentRoute.value.name as string,
|
||||||
|
},
|
||||||
|
});
|
||||||
}, 3000);
|
}, 3000);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
|
|
@ -458,7 +458,7 @@
|
||||||
.arco-tree-node-drag-icon {
|
.arco-tree-node-drag-icon {
|
||||||
@apply cursor-move;
|
@apply cursor-move;
|
||||||
|
|
||||||
right: 6px;
|
right: 16px;
|
||||||
.arco-icon {
|
.arco-icon {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
:popup-visible="currentVisible"
|
:popup-visible="currentVisible"
|
||||||
position="bl"
|
position="bl"
|
||||||
trigger="click"
|
trigger="click"
|
||||||
class="w-[277px]"
|
class="w-[350px]"
|
||||||
:content-class="props.id ? 'move-left' : ''"
|
:content-class="props.id ? 'move-left' : ''"
|
||||||
>
|
>
|
||||||
<template #content>
|
<template #content>
|
||||||
|
@ -18,13 +18,12 @@
|
||||||
:label-col-props="{ span: 0 }"
|
:label-col-props="{ span: 0 }"
|
||||||
:wrapper-col-props="{ span: 24 }"
|
:wrapper-col-props="{ span: 24 }"
|
||||||
>
|
>
|
||||||
<div class="mb-[8px] text-[14px] font-medium text-[var(--color-text-1)]">{{
|
<div class="mb-[8px] text-[14px] font-medium text-[var(--color-text-1)]">
|
||||||
props.id ? t('system.userGroup.rename') : t('system.userGroup.createUserGroup')
|
{{ props.id ? t('system.userGroup.rename') : t('system.userGroup.createUserGroup') }}
|
||||||
}}</div>
|
</div>
|
||||||
<a-form-item field="name" :rules="[{ validator: validateName }]">
|
<a-form-item field="name" :rules="[{ validator: validateName }]">
|
||||||
<a-input
|
<a-input
|
||||||
v-model="form.name"
|
v-model="form.name"
|
||||||
class="w-[243px]"
|
|
||||||
:max-length="255"
|
:max-length="255"
|
||||||
:placeholder="t('system.userGroup.searchHolder')"
|
:placeholder="t('system.userGroup.searchHolder')"
|
||||||
allow-clear
|
allow-clear
|
||||||
|
@ -107,7 +106,7 @@
|
||||||
callback(t('system.userGroup.userGroupNameIsExist', { name: value }));
|
callback(t('system.userGroup.userGroupNameIsExist', { name: value }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (value.length === 255) {
|
if (value.length > 255) {
|
||||||
callback(t('common.nameIsTooLang'));
|
callback(t('common.nameIsTooLang'));
|
||||||
}
|
}
|
||||||
callback();
|
callback();
|
||||||
|
|
|
@ -445,7 +445,13 @@
|
||||||
if (isSelect) {
|
if (isSelect) {
|
||||||
// leftCollapse 切换时不重复数据请求
|
// leftCollapse 切换时不重复数据请求
|
||||||
if (id) {
|
if (id) {
|
||||||
handleListItemClick(res.find((i) => i.id === id) || res[0]);
|
const item = res.find((i) => i.id === id);
|
||||||
|
if (item) {
|
||||||
|
handleListItemClick(item);
|
||||||
|
} else {
|
||||||
|
Message.warning(t('common.resourceDeleted'));
|
||||||
|
handleListItemClick(res[0]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
handleListItemClick(res[0]);
|
handleListItemClick(res[0]);
|
||||||
}
|
}
|
||||||
|
@ -465,8 +471,8 @@
|
||||||
|
|
||||||
// 点击更多操作
|
// 点击更多操作
|
||||||
const handleMoreAction = (item: ActionsItem, id: string, authScope: AuthScopeEnum) => {
|
const handleMoreAction = (item: ActionsItem, id: string, authScope: AuthScopeEnum) => {
|
||||||
|
const tmpObj = userGroupList.value.filter((ele) => ele.id === id)[0];
|
||||||
if (item.eventTag === 'rename') {
|
if (item.eventTag === 'rename') {
|
||||||
const tmpObj = userGroupList.value.filter((ele) => ele.id === id)[0];
|
|
||||||
const visibleItem: PopVisibleItem = { visible: true, authScope, defaultName: tmpObj.name, id };
|
const visibleItem: PopVisibleItem = { visible: true, authScope, defaultName: tmpObj.name, id };
|
||||||
popVisible.value[id] = visibleItem;
|
popVisible.value[id] = visibleItem;
|
||||||
}
|
}
|
||||||
|
@ -485,7 +491,7 @@
|
||||||
}
|
}
|
||||||
openModal({
|
openModal({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
title: t('system.userGroup.isDeleteUserGroup', { name: characterLimit(currentName.value) }),
|
title: t('system.userGroup.isDeleteUserGroup', { name: characterLimit(tmpObj.name) }),
|
||||||
content,
|
content,
|
||||||
okText: t('system.userGroup.confirmDelete'),
|
okText: t('system.userGroup.confirmDelete'),
|
||||||
cancelText: t('system.userGroup.cancel'),
|
cancelText: t('system.userGroup.cancel'),
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<MsRemoveButton
|
<MsRemoveButton
|
||||||
:title="t('system.userGroup.removeName', { name: characterLimit(record.name) })"
|
:title="t('system.userGroup.removeName', { name: characterLimit(record.name) })"
|
||||||
:sub-title-tip="t('system.userGroup.removeTip')"
|
:sub-title-tip="t('system.userGroup.removeTip')"
|
||||||
:disabled="record.userId === 'admin'"
|
:disabled="systemType === AuthScopeEnum.SYSTEM && record.userId === 'admin'"
|
||||||
@ok="handleRemove(record)"
|
@ok="handleRemove(record)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
@ -77,7 +77,7 @@
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const userGroupUsercolumns: MsTableColumn = [
|
const userGroupUserColumns: MsTableColumn = [
|
||||||
{
|
{
|
||||||
title: 'system.userGroup.name',
|
title: 'system.userGroup.name',
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
|
@ -113,7 +113,7 @@
|
||||||
const { propsRes, propsEvent, loadList, setLoadListParams, setKeyword } = useTable(
|
const { propsRes, propsEvent, loadList, setLoadListParams, setKeyword } = useTable(
|
||||||
getRequestBySystemType(),
|
getRequestBySystemType(),
|
||||||
{
|
{
|
||||||
columns: userGroupUsercolumns,
|
columns: userGroupUserColumns,
|
||||||
scroll: { x: '100%', minWidth: 700, y: '100%' },
|
scroll: { x: '100%', minWidth: 700, y: '100%' },
|
||||||
selectable: false,
|
selectable: false,
|
||||||
noDisable: true,
|
noDisable: true,
|
||||||
|
@ -130,7 +130,6 @@
|
||||||
|
|
||||||
const handlePermission = (permission: string[], cb: () => void) => {
|
const handlePermission = (permission: string[], cb: () => void) => {
|
||||||
if (!hasAnyPermission(permission)) {
|
if (!hasAnyPermission(permission)) {
|
||||||
Message.error(t('common.noPermission'));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
cb();
|
cb();
|
||||||
|
|
|
@ -58,10 +58,10 @@
|
||||||
<div class="flex justify-end gap-[16px]">
|
<div class="flex justify-end gap-[16px]">
|
||||||
<a-button type="secondary" @click="back">{{ t('mscard.defaultCancelText') }}</a-button>
|
<a-button type="secondary" @click="back">{{ t('mscard.defaultCancelText') }}</a-button>
|
||||||
<a-button v-if="!props.hideContinue && !props.isEdit" type="secondary" @click="emit('saveAndContinue')">
|
<a-button v-if="!props.hideContinue && !props.isEdit" type="secondary" @click="emit('saveAndContinue')">
|
||||||
{{ t('mscard.defaultSaveAndContinueText') }}
|
{{ props.saveAndContinueText || t('mscard.defaultSaveAndContinueText') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button type="primary" @click="emit('save')">
|
<a-button type="primary" @click="emit('save')">
|
||||||
{{ t(props.isEdit ? 'mscard.defaultUpdate' : 'mscard.defaultConfirm') }}
|
{{ props.saveText || t(props.isEdit ? 'mscard.defaultUpdate' : 'mscard.defaultConfirm') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
</slot>
|
</slot>
|
||||||
|
@ -102,6 +102,8 @@
|
||||||
handleBack: () => void; // 自定义返回按钮触发事件
|
handleBack: () => void; // 自定义返回按钮触发事件
|
||||||
dividerHasPX: boolean; // 分割线是否有左右padding;
|
dividerHasPX: boolean; // 分割线是否有左右padding;
|
||||||
showFullScreen: boolean; // 是否显示全屏按钮
|
showFullScreen: boolean; // 是否显示全屏按钮
|
||||||
|
saveText?: string; // 保存按钮文案
|
||||||
|
saveAndContinueText?: string; // 保存并继续按钮文案
|
||||||
}>
|
}>
|
||||||
>(),
|
>(),
|
||||||
{
|
{
|
||||||
|
@ -151,6 +153,10 @@
|
||||||
// 简单模式没有标题、没有底部
|
// 简单模式没有标题、没有底部
|
||||||
return props.noContentPadding ? 66 + _specialHeight : 114 + _specialHeight;
|
return props.noContentPadding ? 66 + _specialHeight : 114 + _specialHeight;
|
||||||
}
|
}
|
||||||
|
if (props.hideFooter) {
|
||||||
|
// 没有底部
|
||||||
|
return props.noContentPadding ? 120 + _specialHeight : 168 + _specialHeight;
|
||||||
|
}
|
||||||
return 230 + _specialHeight;
|
return 230 + _specialHeight;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,10 @@
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<div ref="tabNav" class="ms-editable-tab-nav">
|
<div ref="tabNav" class="ms-editable-tab-nav">
|
||||||
<div
|
<div
|
||||||
v-for="tab in props.tabs"
|
v-for="tab in tabs"
|
||||||
:key="tab.id"
|
:key="tab.id"
|
||||||
class="ms-editable-tab"
|
class="ms-editable-tab"
|
||||||
:class="{ active: innerActiveTab?.id === tab.id }"
|
:class="{ active: activeTab?.id === tab.id }"
|
||||||
@click="handleTabClick(tab)"
|
@click="handleTabClick(tab)"
|
||||||
>
|
>
|
||||||
<div :draggable="!!tab.draggable" class="flex items-center">
|
<div :draggable="!!tab.draggable" class="flex items-center">
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
</slot>
|
</slot>
|
||||||
<div v-if="tab.unSaved" class="ml-[8px] h-[8px] w-[8px] rounded-full bg-[rgb(var(--primary-5))]"></div>
|
<div v-if="tab.unSaved" class="ml-[8px] h-[8px] w-[8px] rounded-full bg-[rgb(var(--primary-5))]"></div>
|
||||||
<MsButton
|
<MsButton
|
||||||
v-if="props.atLeastOne ? props.tabs.length > 1 && tab.closable : tab.closable !== false"
|
v-if="props.atLeastOne ? tabs.length > 1 && tab.closable : tab.closable !== false"
|
||||||
type="icon"
|
type="icon"
|
||||||
status="secondary"
|
status="secondary"
|
||||||
class="ms-editable-tab-close-button"
|
class="ms-editable-tab-close-button"
|
||||||
|
@ -54,20 +54,20 @@
|
||||||
<a-tooltip
|
<a-tooltip
|
||||||
v-if="!props.readonly && showAdd"
|
v-if="!props.readonly && showAdd"
|
||||||
:content="t('ms.editableTab.limitTip', { max: props.limit })"
|
:content="t('ms.editableTab.limitTip', { max: props.limit })"
|
||||||
:disabled="!props.limit || props.tabs.length >= props.limit"
|
:disabled="!props.limit || tabs.length >= props.limit"
|
||||||
>
|
>
|
||||||
<MsButton
|
<MsButton
|
||||||
type="icon"
|
type="icon"
|
||||||
status="secondary"
|
status="secondary"
|
||||||
class="ms-editable-tab-button !mr-[4px]"
|
class="ms-editable-tab-button !mr-[4px]"
|
||||||
:disabled="!!props.limit && props.tabs.length >= props.limit"
|
:disabled="!!props.limit && tabs.length >= props.limit"
|
||||||
@click="addTab"
|
@click="addTab"
|
||||||
>
|
>
|
||||||
<MsIcon type="icon-icon_add_outlined" />
|
<MsIcon type="icon-icon_add_outlined" />
|
||||||
</MsButton>
|
</MsButton>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<MsMoreAction
|
<MsMoreAction
|
||||||
v-if="!props.hideMoreAction && !props.readonly"
|
v-if="!props.hideMoreAction && !props.readonly && mergedMoreActionList.length > 0"
|
||||||
:list="mergedMoreActionList"
|
:list="mergedMoreActionList"
|
||||||
@select="handleMoreActionSelect"
|
@select="handleMoreActionSelect"
|
||||||
>
|
>
|
||||||
|
@ -95,8 +95,6 @@
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
tabs: TabItem[];
|
|
||||||
activeTab?: TabItem;
|
|
||||||
moreActionList?: ActionsItem[];
|
moreActionList?: ActionsItem[];
|
||||||
showAdd?: boolean; // 是否展示增加tab按钮
|
showAdd?: boolean; // 是否展示增加tab按钮
|
||||||
limit?: number; // 最多可打开的tab数量
|
limit?: number; // 最多可打开的tab数量
|
||||||
|
@ -109,8 +107,6 @@
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'update:tabs', tabs: TabItem[]): void;
|
|
||||||
(e: 'update:activeTab', activeTab: TabItem): void;
|
|
||||||
(e: 'add'): void;
|
(e: 'add'): void;
|
||||||
(e: 'close', item: TabItem): void;
|
(e: 'close', item: TabItem): void;
|
||||||
(e: 'change', item: TabItem): void;
|
(e: 'change', item: TabItem): void;
|
||||||
|
@ -120,8 +116,12 @@
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { openModal } = useModal();
|
const { openModal } = useModal();
|
||||||
|
|
||||||
const innerActiveTab = useVModel(props, 'activeTab', emit);
|
const activeTab = defineModel<TabItem | undefined>('activeTab', {
|
||||||
const innerTabs = useVModel(props, 'tabs', emit);
|
default: undefined,
|
||||||
|
});
|
||||||
|
const tabs = defineModel<TabItem[]>('tabs', {
|
||||||
|
required: true,
|
||||||
|
});
|
||||||
const tabNav = ref<HTMLElement>();
|
const tabNav = ref<HTMLElement>();
|
||||||
const { arrivedState } = useScroll(tabNav);
|
const { arrivedState } = useScroll(tabNav);
|
||||||
const isNotOverflow = computed(() => arrivedState.left && arrivedState.right); // 内容是否溢出,用于判断左右滑动按钮是否展示
|
const isNotOverflow = computed(() => arrivedState.left && arrivedState.right); // 内容是否溢出,用于判断左右滑动按钮是否展示
|
||||||
|
@ -178,6 +178,9 @@
|
||||||
const dl = props.atLeastOne
|
const dl = props.atLeastOne
|
||||||
? defaultMoreActionList.filter((e) => e.eventTag !== 'closeAll')
|
? defaultMoreActionList.filter((e) => e.eventTag !== 'closeAll')
|
||||||
: defaultMoreActionList;
|
: defaultMoreActionList;
|
||||||
|
if (tabs.value.filter((item) => item.closable === true).length === 0) {
|
||||||
|
return props.moreActionList ? [...props.moreActionList] : [];
|
||||||
|
}
|
||||||
return props.moreActionList ? [...dl, ...props.moreActionList] : dl;
|
return props.moreActionList ? [...dl, ...props.moreActionList] : dl;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -185,9 +188,9 @@
|
||||||
* 监听激活的tab变化,滚动到激活的tab
|
* 监听激活的tab变化,滚动到激活的tab
|
||||||
*/
|
*/
|
||||||
watch(
|
watch(
|
||||||
() => props.activeTab,
|
() => activeTab.value,
|
||||||
() => {
|
() => {
|
||||||
useDraggable('.ms-editable-tab-nav', innerTabs, {
|
useDraggable('.ms-editable-tab-nav', tabs, {
|
||||||
ghostClass: 'ms-editable-tab-ghost',
|
ghostClass: 'ms-editable-tab-ghost',
|
||||||
});
|
});
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
|
@ -211,11 +214,11 @@
|
||||||
* 关闭一个tab
|
* 关闭一个tab
|
||||||
*/
|
*/
|
||||||
function closeOneTab(item: TabItem) {
|
function closeOneTab(item: TabItem) {
|
||||||
const index = innerTabs.value.findIndex((e) => e.id === item.id);
|
const index = tabs.value.findIndex((e) => e.id === item.id);
|
||||||
innerTabs.value.splice(index, 1);
|
tabs.value.splice(index, 1);
|
||||||
if (innerActiveTab.value?.id === item.id && innerTabs.value[0]) {
|
if (activeTab.value?.id === item.id && tabs.value[0]) {
|
||||||
[innerActiveTab.value] = innerTabs.value;
|
[activeTab.value] = tabs.value;
|
||||||
emit('change', innerTabs.value[0]);
|
emit('change', tabs.value[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,8 +244,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleTabClick(item: TabItem) {
|
function handleTabClick(item: TabItem) {
|
||||||
if (innerActiveTab.value?.id !== item.id) {
|
if (activeTab.value?.id !== item.id) {
|
||||||
innerActiveTab.value = item;
|
activeTab.value = item;
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
tabNav.value?.querySelector('.tab.active')?.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
tabNav.value?.querySelector('.tab.active')?.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
});
|
});
|
||||||
|
@ -256,14 +259,12 @@
|
||||||
function executeAction(event: ActionsItem) {
|
function executeAction(event: ActionsItem) {
|
||||||
switch (event.eventTag) {
|
switch (event.eventTag) {
|
||||||
case 'closeAll':
|
case 'closeAll':
|
||||||
innerTabs.value = innerTabs.value.filter((item) => item.closable === false);
|
tabs.value = tabs.value.filter((item) => item.closable === false);
|
||||||
[innerActiveTab.value] = innerTabs.value;
|
[activeTab.value] = tabs.value;
|
||||||
emit('change', innerActiveTab.value);
|
emit('change', activeTab.value);
|
||||||
break;
|
break;
|
||||||
case 'closeOther':
|
case 'closeOther':
|
||||||
innerTabs.value = innerTabs.value.filter(
|
tabs.value = tabs.value.filter((item) => item.id === activeTab.value?.id || item.closable === false);
|
||||||
(item) => item.id === innerActiveTab.value?.id || item.closable === false
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
emit('moreActionSelect', event);
|
emit('moreActionSelect', event);
|
||||||
|
@ -276,9 +277,8 @@
|
||||||
*/
|
*/
|
||||||
function handleMoreActionSelect(event: ActionsItem) {
|
function handleMoreActionSelect(event: ActionsItem) {
|
||||||
if (
|
if (
|
||||||
(event.eventTag === 'closeAll' && innerTabs.value.some((item) => item.unSaved)) ||
|
(event.eventTag === 'closeAll' && tabs.value.some((item) => item.unSaved)) ||
|
||||||
(event.eventTag === 'closeOther' &&
|
(event.eventTag === 'closeOther' && tabs.value.some((item) => item.unSaved && item.id !== activeTab.value?.id))
|
||||||
innerTabs.value.some((item) => item.unSaved && item.id !== innerActiveTab.value?.id))
|
|
||||||
) {
|
) {
|
||||||
openModal({
|
openModal({
|
||||||
title: t('common.tip'),
|
title: t('common.tip'),
|
||||||
|
|
|
@ -3,14 +3,14 @@ import { onBeforeRouteLeave } from 'vue-router';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useModal from '@/hooks/useModal';
|
import useModal from '@/hooks/useModal';
|
||||||
|
|
||||||
const isSave = ref(false);
|
|
||||||
|
|
||||||
// 离开页面确认提示
|
// 离开页面确认提示
|
||||||
export default function useLeaveUnSaveTip() {
|
export default function useLeaveUnSaveTip() {
|
||||||
const { openModal } = useModal();
|
const { openModal } = useModal();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const setState = (flag: boolean) => {
|
const isSave = ref(true);
|
||||||
|
|
||||||
|
const setIsSave = (flag: boolean) => {
|
||||||
isSave.value = flag;
|
isSave.value = flag;
|
||||||
};
|
};
|
||||||
onBeforeRouteLeave((to, from, next) => {
|
onBeforeRouteLeave((to, from, next) => {
|
||||||
|
@ -40,6 +40,6 @@ export default function useLeaveUnSaveTip() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
setState,
|
setIsSave,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { RouteLocationNormalized, RouteRecordRaw } from 'vue-router';
|
import { RouteLocationNormalized, RouteRecordRaw } from 'vue-router';
|
||||||
import { includes } from 'lodash-es';
|
|
||||||
|
|
||||||
import { firstLevelMenu } from '@/config/permission';
|
import { firstLevelMenu } from '@/config/permission';
|
||||||
import { hasAnyPermission, topLevelMenuHasPermission } from '@/utils/permission';
|
import { hasAnyPermission, topLevelMenuHasPermission } from '@/utils/permission';
|
||||||
|
|
|
@ -151,4 +151,5 @@ export default {
|
||||||
'The content of some tabs has not been saved. The unsaved content will be lost after leaving. Are you sure you want to leave?',
|
'The content of some tabs has not been saved. The unsaved content will be lost after leaving. Are you sure you want to leave?',
|
||||||
'common.image': 'Image',
|
'common.image': 'Image',
|
||||||
'common.text': 'Text',
|
'common.text': 'Text',
|
||||||
|
'common.resourceDeleted': 'Resource has been deleted',
|
||||||
};
|
};
|
||||||
|
|
|
@ -151,4 +151,5 @@ export default {
|
||||||
'common.unsavedLeave': '有标签页的内容未保存,离开后未保存的内容将丢失,确定要离开吗?',
|
'common.unsavedLeave': '有标签页的内容未保存,离开后未保存的内容将丢失,确定要离开吗?',
|
||||||
'common.image': '图片',
|
'common.image': '图片',
|
||||||
'common.text': '文本',
|
'common.text': '文本',
|
||||||
|
'common.resourceDeleted': '资源已被删除',
|
||||||
};
|
};
|
||||||
|
|
|
@ -51,6 +51,7 @@ export interface ResourcePoolItem extends ResourcePoolInfo {
|
||||||
|
|
||||||
export type ResourcePoolDetail = Omit<ResourcePoolInfo, 'testResourceDTO'> & {
|
export type ResourcePoolDetail = Omit<ResourcePoolInfo, 'testResourceDTO'> & {
|
||||||
id: string;
|
id: string;
|
||||||
|
deleted: boolean;
|
||||||
testResourceReturnDTO: TestResourceDTO;
|
testResourceReturnDTO: TestResourceDTO;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -525,7 +525,6 @@
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
data: ExecuteConditionProcessor;
|
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
response?: string; // 响应内容
|
response?: string; // 响应内容
|
||||||
heightUsed?: number;
|
heightUsed?: number;
|
||||||
|
@ -542,7 +541,6 @@
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'update:data', data: ExecuteConditionProcessor): void;
|
|
||||||
(e: 'copy'): void;
|
(e: 'copy'): void;
|
||||||
(e: 'delete', id: number): void;
|
(e: 'delete', id: number): void;
|
||||||
(e: 'change'): void;
|
(e: 'change'): void;
|
||||||
|
@ -551,30 +549,36 @@
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const currentEnvConfig = inject<Ref<EnvConfig>>('currentEnvConfig');
|
const currentEnvConfig = inject<Ref<EnvConfig>>('currentEnvConfig');
|
||||||
const condition = useVModel(props, 'data', emit);
|
const condition = defineModel<ExecuteConditionProcessor>('data', {
|
||||||
|
required: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
function filterDataSource() {
|
||||||
|
if (condition.value.processorType === RequestConditionProcessor.SQL && condition.value.dataSourceId) {
|
||||||
|
// 如果是SQL类型的条件且已选数据源,需要根据环境切换数据源
|
||||||
|
const dataSourceItem = currentEnvConfig?.value.dataSources.find(
|
||||||
|
(item) => item.dataSource === condition.value.dataSourceName
|
||||||
|
);
|
||||||
|
if (currentEnvConfig?.value.dataSources.length === 0) {
|
||||||
|
// 如果没有数据源,就清除已选的数据源
|
||||||
|
condition.value.dataSourceName = '';
|
||||||
|
condition.value.dataSourceId = '';
|
||||||
|
} else if (dataSourceItem) {
|
||||||
|
// 每次初始化都去查找一下最新的数据源,因为切换环境的时候数据源也需要切换
|
||||||
|
condition.value.dataSourceName = dataSourceItem.dataSource;
|
||||||
|
condition.value.dataSourceId = dataSourceItem.id;
|
||||||
|
} else if (currentEnvConfig && currentEnvConfig.value.dataSources.length > 0) {
|
||||||
|
// 如果没有找到,就默认取第一个数据源
|
||||||
|
condition.value.dataSourceName = currentEnvConfig.value.dataSources[0].dataSource;
|
||||||
|
condition.value.dataSourceId = currentEnvConfig.value.dataSources[0].id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => currentEnvConfig?.value,
|
() => currentEnvConfig?.value,
|
||||||
() => {
|
() => {
|
||||||
if (condition.value.processorType === RequestConditionProcessor.SQL && condition.value.dataSourceId) {
|
filterDataSource();
|
||||||
// 如果是SQL类型的条件且已选数据源,需要根据环境切换数据源
|
|
||||||
const dataSourceItem = currentEnvConfig?.value.dataSources.find(
|
|
||||||
(item) => item.dataSource === condition.value.dataSourceName
|
|
||||||
);
|
|
||||||
if (currentEnvConfig?.value.dataSources.length === 0) {
|
|
||||||
// 如果没有数据源,就清除已选的数据源
|
|
||||||
condition.value.dataSourceName = '';
|
|
||||||
condition.value.dataSourceId = '';
|
|
||||||
} else if (dataSourceItem) {
|
|
||||||
// 每次初始化都去查找一下最新的数据源,因为切换环境的时候数据源也需要切换
|
|
||||||
condition.value.dataSourceName = dataSourceItem.dataSource;
|
|
||||||
condition.value.dataSourceId = dataSourceItem.id;
|
|
||||||
} else if (currentEnvConfig && currentEnvConfig.value.dataSources.length > 0) {
|
|
||||||
// 如果没有找到,就默认取第一个数据源
|
|
||||||
condition.value.dataSourceName = currentEnvConfig.value.dataSources[0].dataSource;
|
|
||||||
condition.value.dataSourceId = currentEnvConfig.value.dataSources[0].id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
immediate: true,
|
immediate: true,
|
||||||
|
@ -582,6 +586,13 @@
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => condition.value.id,
|
||||||
|
() => {
|
||||||
|
filterDataSource();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// 是否显示脚本名称编辑框
|
// 是否显示脚本名称编辑框
|
||||||
const isShowEditScriptNameInput = ref(false);
|
const isShowEditScriptNameInput = ref(false);
|
||||||
const scriptNameInputRef = ref<InputInstance>();
|
const scriptNameInputRef = ref<InputInstance>();
|
||||||
|
@ -1003,12 +1014,14 @@ if (!result){
|
||||||
|
|
||||||
const protocolList = ref<ProtocolItem[]>([]);
|
const protocolList = ref<ProtocolItem[]>([]);
|
||||||
onBeforeMount(async () => {
|
onBeforeMount(async () => {
|
||||||
try {
|
if (props.showPrePostRequest) {
|
||||||
// TODO:数据从外面传进来
|
try {
|
||||||
protocolList.value = await getProtocolList(appStore.currentOrgId);
|
// TODO:数据从外面传进来
|
||||||
} catch (error) {
|
protocolList.value = await getProtocolList(appStore.currentOrgId);
|
||||||
// eslint-disable-next-line no-console
|
} catch (error) {
|
||||||
console.log(error);
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
watch(
|
watch(
|
||||||
|
|
|
@ -17,10 +17,10 @@
|
||||||
<slot name="titleRight"></slot>
|
<slot name="titleRight"></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="data.length > 0 && activeItem" class="flex h-[calc(100%-40px)] w-full gap-[8px]">
|
<div v-if="list.length > 0 && activeItem" class="flex h-[calc(100%-40px)] w-full gap-[8px]">
|
||||||
<div class="h-full w-[20%] min-w-[220px]">
|
<div class="h-full w-[20%] min-w-[220px]">
|
||||||
<conditionList
|
<conditionList
|
||||||
v-model:list="data"
|
v-model:list="list"
|
||||||
:disabled="props.disabled"
|
:disabled="props.disabled"
|
||||||
:active-id="activeItemId"
|
:active-id="activeItemId"
|
||||||
:show-associated-scene="props.showAssociatedScene"
|
:show-associated-scene="props.showAssociatedScene"
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
<conditionContent
|
<conditionContent
|
||||||
v-model:data="activeItem"
|
v-model:data="activeItem"
|
||||||
:disabled="props.disabled"
|
:disabled="props.disabled"
|
||||||
:total-list="data"
|
:total-list="list"
|
||||||
:response="props.response"
|
:response="props.response"
|
||||||
:height-used="props.heightUsed"
|
:height-used="props.heightUsed"
|
||||||
:show-associated-scene="props.showAssociatedScene"
|
:show-associated-scene="props.showAssociatedScene"
|
||||||
|
@ -57,12 +57,11 @@
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
|
||||||
import { ConditionType, ExecuteConditionProcessor, RegexExtract } from '@/models/apiTest/common';
|
import { ConditionType, ExecuteConditionProcessor, RegexExtract } from '@/models/apiTest/common';
|
||||||
import { RequestConditionProcessor, RequestExtractExpressionEnum, RequestExtractScope } from '@/enums/apiEnum';
|
import { RequestConditionProcessor, RequestExtractScope } from '@/enums/apiEnum';
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
list: ExecuteConditionProcessor[];
|
|
||||||
conditionTypes: Array<ConditionType>;
|
conditionTypes: Array<ConditionType>;
|
||||||
addText: string;
|
addText: string;
|
||||||
requestRadioTextProps?: Record<string, any>;
|
requestRadioTextProps?: Record<string, any>;
|
||||||
|
@ -77,16 +76,15 @@
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'update:list', list: ExecuteConditionProcessor[]): void;
|
|
||||||
(e: 'change'): void;
|
(e: 'change'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const data = defineModel<ExecuteConditionProcessor[]>('list', {
|
const list = defineModel<ExecuteConditionProcessor[]>('list', {
|
||||||
required: true,
|
required: true,
|
||||||
});
|
});
|
||||||
const activeItem = ref<ExecuteConditionProcessor>(data.value[0]);
|
const activeItem = ref<ExecuteConditionProcessor>(list.value[0]);
|
||||||
const activeItemId = computed(() => activeItem.value?.id);
|
const activeItemId = computed(() => activeItem.value?.id);
|
||||||
|
|
||||||
function handleListActiveChange(item: ExecuteConditionProcessor) {
|
function handleListActiveChange(item: ExecuteConditionProcessor) {
|
||||||
|
@ -101,8 +99,8 @@
|
||||||
...cloneDeep(activeItem.value),
|
...cloneDeep(activeItem.value),
|
||||||
id: new Date().getTime(),
|
id: new Date().getTime(),
|
||||||
};
|
};
|
||||||
data.value.push(copyItem as ExecuteConditionProcessor);
|
list.value.push(copyItem as ExecuteConditionProcessor);
|
||||||
activeItem.value = copyItem as ExecuteConditionProcessor;
|
activeItem.value = list.value[list.value.length - 1];
|
||||||
emit('change');
|
emit('change');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,9 +108,9 @@
|
||||||
* 删除列表项
|
* 删除列表项
|
||||||
*/
|
*/
|
||||||
function deleteListItem(id: string | number) {
|
function deleteListItem(id: string | number) {
|
||||||
data.value = data.value.filter((precondition) => precondition.id !== activeItemId.value);
|
list.value = list.value.filter((precondition) => precondition.id !== activeItemId.value);
|
||||||
if (activeItemId.value === id) {
|
if (activeItemId.value === id) {
|
||||||
[activeItem.value] = data.value;
|
[activeItem.value] = list.value;
|
||||||
}
|
}
|
||||||
emit('change');
|
emit('change');
|
||||||
}
|
}
|
||||||
|
@ -131,10 +129,10 @@
|
||||||
} else if (props.showPrePostRequest) {
|
} else if (props.showPrePostRequest) {
|
||||||
type = RequestConditionProcessor.REQUEST_SCRIPT;
|
type = RequestConditionProcessor.REQUEST_SCRIPT;
|
||||||
}
|
}
|
||||||
const isExistPre = data.value.filter(
|
const isExistPre = list.value.filter(
|
||||||
(item) => item.beforeStepScript && item.processorType === RequestConditionProcessor.REQUEST_SCRIPT
|
(item) => item.beforeStepScript && item.processorType === RequestConditionProcessor.REQUEST_SCRIPT
|
||||||
).length;
|
).length;
|
||||||
const isExistPost = data.value.filter(
|
const isExistPost = list.value.filter(
|
||||||
(item) => !item.beforeStepScript && item.processorType === RequestConditionProcessor.REQUEST_SCRIPT
|
(item) => !item.beforeStepScript && item.processorType === RequestConditionProcessor.REQUEST_SCRIPT
|
||||||
).length;
|
).length;
|
||||||
// 如果是场景或者是请求类型的 需要限制前后脚本类型只能为一前一后
|
// 如果是场景或者是请求类型的 需要限制前后脚本类型只能为一前一后
|
||||||
|
@ -142,7 +140,7 @@
|
||||||
if (isExistPre && isExistPost && props.showPrePostRequest) {
|
if (isExistPre && isExistPost && props.showPrePostRequest) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
data.value.push({
|
list.value.push({
|
||||||
id,
|
id,
|
||||||
processorType: type,
|
processorType: type,
|
||||||
name: t('apiTestDebug.preconditionScriptName'),
|
name: t('apiTestDebug.preconditionScriptName'),
|
||||||
|
@ -165,12 +163,12 @@
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case RequestConditionProcessor.SQL:
|
case RequestConditionProcessor.SQL:
|
||||||
const isSQL = data.value.find((item) => item.processorType === RequestConditionProcessor.SQL);
|
const isSQL = list.value.find((item) => item.processorType === RequestConditionProcessor.SQL);
|
||||||
|
|
||||||
if (props.showPrePostRequest && isSQL) {
|
if (props.showPrePostRequest && isSQL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
data.value.push({
|
list.value.push({
|
||||||
id,
|
id,
|
||||||
processorType: RequestConditionProcessor.SQL,
|
processorType: RequestConditionProcessor.SQL,
|
||||||
enableCommonScript: false,
|
enableCommonScript: false,
|
||||||
|
@ -189,7 +187,7 @@
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case RequestConditionProcessor.TIME_WAITING:
|
case RequestConditionProcessor.TIME_WAITING:
|
||||||
data.value.push({
|
list.value.push({
|
||||||
id,
|
id,
|
||||||
processorType: RequestConditionProcessor.TIME_WAITING,
|
processorType: RequestConditionProcessor.TIME_WAITING,
|
||||||
associateScenarioResult: false,
|
associateScenarioResult: false,
|
||||||
|
@ -200,11 +198,11 @@
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case RequestConditionProcessor.EXTRACT:
|
case RequestConditionProcessor.EXTRACT:
|
||||||
const isEXTRACT = data.value.find((item) => item.processorType === RequestConditionProcessor.EXTRACT);
|
const isEXTRACT = list.value.find((item) => item.processorType === RequestConditionProcessor.EXTRACT);
|
||||||
if (isEXTRACT) {
|
if (isEXTRACT) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
data.value.push({
|
list.value.push({
|
||||||
id,
|
id,
|
||||||
processorType: RequestConditionProcessor.EXTRACT,
|
processorType: RequestConditionProcessor.EXTRACT,
|
||||||
enableCommonScript: false,
|
enableCommonScript: false,
|
||||||
|
@ -218,14 +216,14 @@
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
activeItem.value = data.value[data.value.length - 1];
|
activeItem.value = list.value[list.value.length - 1];
|
||||||
emit('change');
|
emit('change');
|
||||||
}
|
}
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
// 后台存储无id,渲染时需要手动添加一次
|
// 后台存储无id,渲染时需要手动添加一次
|
||||||
let hasNoIdItem = false;
|
let hasNoIdItem = false;
|
||||||
const tempArr = props.list.map((item, i) => {
|
const tempArr = list.value.map((item, i) => {
|
||||||
if (!item.id) {
|
if (!item.id) {
|
||||||
hasNoIdItem = true;
|
hasNoIdItem = true;
|
||||||
return {
|
return {
|
||||||
|
@ -241,8 +239,8 @@
|
||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
if (hasNoIdItem) {
|
if (hasNoIdItem) {
|
||||||
data.value = tempArr.map((e) => e);
|
list.value = tempArr;
|
||||||
[activeItem.value] = data.value;
|
[activeItem.value] = list.value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<MsList
|
<MsList
|
||||||
v-model:active-item-key="activeItem.id"
|
v-model:active-item-key="activeItem.id"
|
||||||
v-model:focus-item-key="focusItemKey"
|
v-model:focus-item-key="focusItemKey"
|
||||||
v-model:data="data"
|
v-model:data="list"
|
||||||
mode="static"
|
mode="static"
|
||||||
item-key-field="id"
|
item-key-field="id"
|
||||||
:disabled="props.disabled"
|
:disabled="props.disabled"
|
||||||
|
@ -59,7 +59,6 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useVModel } from '@vueuse/core';
|
|
||||||
import { cloneDeep } from 'lodash-es';
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
import MsList from '@/components/pure/ms-list/index.vue';
|
import MsList from '@/components/pure/ms-list/index.vue';
|
||||||
|
@ -74,20 +73,20 @@
|
||||||
import { RequestConditionProcessor } from '@/enums/apiEnum';
|
import { RequestConditionProcessor } from '@/enums/apiEnum';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
list: ExecuteConditionProcessor[];
|
|
||||||
activeId?: string | number;
|
activeId?: string | number;
|
||||||
showAssociatedScene?: boolean;
|
showAssociatedScene?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
showPrePostRequest?: boolean; // 是否展示前后置请求忽略选项
|
showPrePostRequest?: boolean; // 是否展示前后置请求忽略选项
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'update:list', list: ExecuteConditionProcessor[]): void;
|
|
||||||
(e: 'activeChange', item: ExecuteConditionProcessor): void;
|
(e: 'activeChange', item: ExecuteConditionProcessor): void;
|
||||||
(e: 'change'): void;
|
(e: 'change'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const data = useVModel(props, 'list', emit);
|
const list = defineModel<ExecuteConditionProcessor[]>('list', {
|
||||||
|
required: true,
|
||||||
|
});
|
||||||
const { openModal } = useModal();
|
const { openModal } = useModal();
|
||||||
|
|
||||||
// 当前聚焦的列表项
|
// 当前聚焦的列表项
|
||||||
|
@ -98,11 +97,11 @@
|
||||||
const hasPreAndPost = computed(() => {
|
const hasPreAndPost = computed(() => {
|
||||||
if (props.showPrePostRequest) {
|
if (props.showPrePostRequest) {
|
||||||
const hasPre =
|
const hasPre =
|
||||||
data.value.filter(
|
list.value.filter(
|
||||||
(item) => item.beforeStepScript && item.processorType === RequestConditionProcessor.REQUEST_SCRIPT
|
(item) => item.beforeStepScript && item.processorType === RequestConditionProcessor.REQUEST_SCRIPT
|
||||||
).length > 0;
|
).length > 0;
|
||||||
const hasPost =
|
const hasPost =
|
||||||
data.value.filter(
|
list.value.filter(
|
||||||
(item) => !item.beforeStepScript && item.processorType === RequestConditionProcessor.REQUEST_SCRIPT
|
(item) => !item.beforeStepScript && item.processorType === RequestConditionProcessor.REQUEST_SCRIPT
|
||||||
).length > 0;
|
).length > 0;
|
||||||
if (hasPre && hasPost) {
|
if (hasPre && hasPost) {
|
||||||
|
@ -114,12 +113,12 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
const hasEXTRACT = computed(() => {
|
const hasEXTRACT = computed(() => {
|
||||||
return data.value.filter((item: any) => item.processorType === RequestConditionProcessor.EXTRACT).length > 0;
|
return list.value.filter((item: any) => item.processorType === RequestConditionProcessor.EXTRACT).length > 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
const hasSql = computed(
|
const hasSql = computed(
|
||||||
() =>
|
() =>
|
||||||
data.value.filter((item: any) => item.processorType === RequestConditionProcessor.SQL).length > 0 &&
|
list.value.filter((item: any) => item.processorType === RequestConditionProcessor.SQL).length > 0 &&
|
||||||
props.showPrePostRequest
|
props.showPrePostRequest
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -139,7 +138,7 @@
|
||||||
let moreActions: ActionsItem[] = [...itemMoreActions];
|
let moreActions: ActionsItem[] = [...itemMoreActions];
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
activeItem.value = data.value.find((item) => item.id === props.activeId) || data.value[0] || {};
|
activeItem.value = list.value.find((item) => item.id === props.activeId) || list.value[0] || {};
|
||||||
emit('activeChange', activeItem.value);
|
emit('activeChange', activeItem.value);
|
||||||
if (hasPreAndPost.value || hasEXTRACT.value || hasSql.value) {
|
if (hasPreAndPost.value || hasEXTRACT.value || hasSql.value) {
|
||||||
moreActions = itemMoreActions.slice(-1);
|
moreActions = itemMoreActions.slice(-1);
|
||||||
|
@ -162,10 +161,10 @@
|
||||||
...cloneDeep(item),
|
...cloneDeep(item),
|
||||||
id: new Date().getTime(),
|
id: new Date().getTime(),
|
||||||
};
|
};
|
||||||
const isExistPre = data.value.filter(
|
const isExistPre = list.value.filter(
|
||||||
(current) => current.beforeStepScript && current.processorType === RequestConditionProcessor.REQUEST_SCRIPT
|
(current) => current.beforeStepScript && current.processorType === RequestConditionProcessor.REQUEST_SCRIPT
|
||||||
).length;
|
).length;
|
||||||
const isExistPost = data.value.filter(
|
const isExistPost = list.value.filter(
|
||||||
(current) => !current.beforeStepScript && current.processorType === RequestConditionProcessor.REQUEST_SCRIPT
|
(current) => !current.beforeStepScript && current.processorType === RequestConditionProcessor.REQUEST_SCRIPT
|
||||||
).length;
|
).length;
|
||||||
// 如果是场景或者是请求类型的 需要限制前后脚本类型只能为一前一后
|
// 如果是场景或者是请求类型的 需要限制前后脚本类型只能为一前一后
|
||||||
|
@ -180,9 +179,9 @@
|
||||||
id: new Date().getTime(),
|
id: new Date().getTime(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const copyIndex = data.value.findIndex((e: ExecuteConditionProcessor) => e.id === item.id);
|
const copyIndex = list.value.findIndex((e: ExecuteConditionProcessor) => e.id === item.id);
|
||||||
if (copyIndex > -1) {
|
if (copyIndex > -1) {
|
||||||
data.value.splice(copyIndex, 0, copyItem);
|
list.value.splice(copyIndex, 0, copyItem);
|
||||||
activeItem.value = copyItem;
|
activeItem.value = copyItem;
|
||||||
emit('activeChange', activeItem.value);
|
emit('activeChange', activeItem.value);
|
||||||
}
|
}
|
||||||
|
@ -193,9 +192,9 @@
|
||||||
* @param item 列表项
|
* @param item 列表项
|
||||||
*/
|
*/
|
||||||
function deleteListItem(item: ExecuteConditionProcessor) {
|
function deleteListItem(item: ExecuteConditionProcessor) {
|
||||||
data.value = data.value.filter((precondition) => precondition.id !== item.id);
|
list.value = list.value.filter((precondition) => precondition.id !== item.id);
|
||||||
if (activeItem.value.id === item.id) {
|
if (activeItem.value.id === item.id) {
|
||||||
[activeItem.value] = data.value;
|
[activeItem.value] = list.value;
|
||||||
}
|
}
|
||||||
emit('activeChange', activeItem.value);
|
emit('activeChange', activeItem.value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<a-select
|
<a-select
|
||||||
v-model:model-value="currentEnv"
|
v-model:model-value="innerCurrentEnv"
|
||||||
:options="envOptions"
|
:options="envOptions"
|
||||||
class="!w-[200px] pl-0 pr-[8px]"
|
class="!w-[200px] pl-0 pr-[8px]"
|
||||||
:loading="envLoading"
|
:loading="envLoading"
|
||||||
allow-search
|
allow-search
|
||||||
@change="initEnvironment"
|
@change="(val) => initEnvironment(val as string)"
|
||||||
@popup-visible-change="popupVisibleChange"
|
@popup-visible-change="popupVisibleChange"
|
||||||
>
|
>
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
|
@ -28,23 +28,36 @@
|
||||||
import { EnvConfig } from '@/models/projectManagement/environmental';
|
import { EnvConfig } from '@/models/projectManagement/environmental';
|
||||||
import { ProjectManagementRouteEnum } from '@/enums/routeEnum';
|
import { ProjectManagementRouteEnum } from '@/enums/routeEnum';
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
currentEnv?: string;
|
||||||
|
setDefaultEnv?: boolean; // 是否设置默认选中环境,当传入的currentEnv为空时根据此属性判断是否需要将currentEnv设置为第一个环境
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
setDefaultEnv: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'update:currentEnv', val: string): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const { openNewPage } = useOpenNewPage();
|
const { openNewPage } = useOpenNewPage();
|
||||||
|
|
||||||
const currentEnv = defineModel<string>('currentEnv', { default: '' });
|
const innerCurrentEnv = ref(props.currentEnv || '');
|
||||||
const currentEnvConfig = defineModel<EnvConfig>('currentEnvConfig', {
|
const currentEnvConfig = defineModel<EnvConfig>('currentEnvConfig', {
|
||||||
default: {},
|
default: {},
|
||||||
});
|
});
|
||||||
const envLoading = ref(false);
|
const envLoading = ref(false);
|
||||||
const envOptions = ref<SelectOptionData[]>([]);
|
const envOptions = ref<SelectOptionData[]>([]);
|
||||||
|
|
||||||
async function initEnvironment() {
|
async function initEnvironment(id: string) {
|
||||||
try {
|
try {
|
||||||
const res = await getEnvironment(currentEnv.value);
|
const res = await getEnvironment(id);
|
||||||
currentEnvConfig.value = {
|
currentEnvConfig.value = {
|
||||||
...res,
|
...res,
|
||||||
id: currentEnv.value,
|
id,
|
||||||
name: envOptions.value.find((item) => item.value === currentEnv.value)?.label || '',
|
name: envOptions.value.find((item) => item.value === id)?.label || '',
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
@ -60,12 +73,10 @@
|
||||||
label: item.name,
|
label: item.name,
|
||||||
value: item.id,
|
value: item.id,
|
||||||
}));
|
}));
|
||||||
currentEnv.value = currentEnv.value.length ? currentEnv.value : res[0]?.id;
|
if (!innerCurrentEnv.value) {
|
||||||
nextTick(() => {
|
innerCurrentEnv.value = res[0]?.id;
|
||||||
if (currentEnv.value) {
|
}
|
||||||
initEnvironment();
|
initEnvironment(innerCurrentEnv.value || res[0]?.id);
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
@ -85,14 +96,24 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => currentEnv.value,
|
() => props.currentEnv,
|
||||||
(val) => {
|
(val) => {
|
||||||
if (!val) {
|
if (!val) {
|
||||||
currentEnv.value = (envOptions.value[0]?.value as string) || '';
|
if (props.setDefaultEnv) {
|
||||||
|
innerCurrentEnv.value = (envOptions.value[0]?.value as string) || '';
|
||||||
|
initEnvironment((envOptions.value[0]?.value as string) || '');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
innerCurrentEnv.value = val;
|
||||||
|
initEnvironment(val);
|
||||||
}
|
}
|
||||||
nextTick(() => {
|
}
|
||||||
initEnvironment();
|
);
|
||||||
});
|
|
||||||
|
watch(
|
||||||
|
() => innerCurrentEnv.value,
|
||||||
|
(val) => {
|
||||||
|
emit('update:currentEnv', val);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -838,10 +838,12 @@
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
|
const lastTwoIsSame =
|
||||||
|
arr.length >= 2 && filterKeyValParams([arr[arr.length - 2]], arr[arr.length - 1]).lastDataIsDefault;
|
||||||
if (
|
if (
|
||||||
!filterKeyValParams(arr, props.defaultParamItem).lastDataIsDefault &&
|
!filterKeyValParams(arr, props.defaultParamItem).lastDataIsDefault &&
|
||||||
!props.isTreeTable &&
|
!props.isTreeTable &&
|
||||||
!filterKeyValParams([arr[arr.length - 2], arr[arr.length - 1]], arr[arr.length - 1]).lastDataIsDefault // 为了判断最后俩行是否一致(因为下拉框切换会新增一行一样的数据,此时最后一条数据与默认数据是不一样的)
|
!lastTwoIsSame // 为了判断最后俩行是否一致(因为下拉框切换会新增一行一样的数据,此时最后一条数据与默认数据是不一样的)
|
||||||
) {
|
) {
|
||||||
addTableLine(arr.length - 1, false, true);
|
addTableLine(arr.length - 1, false, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
title: 'apiTestDebug.status',
|
title: 'apiTestDebug.status',
|
||||||
dataIndex: 'pass',
|
dataIndex: 'pass',
|
||||||
slotName: 'status',
|
slotName: 'status',
|
||||||
width: 100,
|
width: 120,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'apiTestDebug.reason',
|
title: 'apiTestDebug.reason',
|
||||||
|
|
|
@ -277,22 +277,24 @@
|
||||||
const { url, headers, queryParameters } = parseCurlScript(curlCode.value);
|
const { url, headers, queryParameters } = parseCurlScript(curlCode.value);
|
||||||
addDebugTab({
|
addDebugTab({
|
||||||
url,
|
url,
|
||||||
headers: headers?.map((e) => ({
|
headers:
|
||||||
contentType: RequestContentTypeEnum.TEXT,
|
headers?.map((e) => ({
|
||||||
description: '',
|
contentType: RequestContentTypeEnum.TEXT,
|
||||||
enable: true,
|
description: '',
|
||||||
...e,
|
enable: true,
|
||||||
})),
|
...e,
|
||||||
query: queryParameters?.map((e) => ({
|
})) || [],
|
||||||
paramType: RequestParamsType.STRING,
|
query:
|
||||||
description: '',
|
queryParameters?.map((e) => ({
|
||||||
required: false,
|
paramType: RequestParamsType.STRING,
|
||||||
maxLength: undefined,
|
description: '',
|
||||||
minLength: undefined,
|
required: false,
|
||||||
encode: false,
|
maxLength: undefined,
|
||||||
enable: true,
|
minLength: undefined,
|
||||||
...e,
|
encode: false,
|
||||||
})),
|
enable: true,
|
||||||
|
...e,
|
||||||
|
})) || [],
|
||||||
});
|
});
|
||||||
curlCode.value = '';
|
curlCode.value = '';
|
||||||
importDrawerVisible.value = false;
|
importDrawerVisible.value = false;
|
||||||
|
|
|
@ -314,11 +314,12 @@
|
||||||
{{ t('apiTestManagement.timeTaskList') }}
|
{{ t('apiTestManagement.timeTaskList') }}
|
||||||
<a-input-search
|
<a-input-search
|
||||||
v-model:model-value="keyword"
|
v-model:model-value="keyword"
|
||||||
:placeholder="t('apiTestManagement.searchPlaceholder')"
|
:placeholder="t('apiTestManagement.searchTaskPlaceholder')"
|
||||||
allow-clear
|
allow-clear
|
||||||
class="mr-[8px] w-[240px]"
|
class="mr-[8px] w-[240px]"
|
||||||
@search="loadTaskList"
|
@search="loadTaskList"
|
||||||
@press-enter="loadTaskList"
|
@press-enter="loadTaskList"
|
||||||
|
@clear="loadTaskList"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<ms-base-table v-bind="propsRes" no-disable v-on="propsEvent">
|
<ms-base-table v-bind="propsRes" no-disable v-on="propsEvent">
|
||||||
|
@ -437,7 +438,7 @@
|
||||||
{ label: t('apiTestManagement.timeTaskTwelveHour'), value: '0 0 0/12 * * ?' },
|
{ label: t('apiTestManagement.timeTaskTwelveHour'), value: '0 0 0/12 * * ?' },
|
||||||
{ label: t('apiTestManagement.timeTaskDay'), value: '0 0 0 * * ?' },
|
{ label: t('apiTestManagement.timeTaskDay'), value: '0 0 0 * * ?' },
|
||||||
];
|
];
|
||||||
const cronValue = ref('0 0 0/1 * * ? ');
|
const cronValue = ref('0 0 0/1 * * ?');
|
||||||
const importLoading = ref(false);
|
const importLoading = ref(false);
|
||||||
const taskDrawerVisible = ref(false);
|
const taskDrawerVisible = ref(false);
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<a-form-item
|
<a-form-item
|
||||||
field="name"
|
field="name"
|
||||||
:label="t('apiTestManagement.apiName')"
|
:label="t('apiTestManagement.apiName')"
|
||||||
class="mb-[16px] w-[80%]"
|
class="mb-[16px] w-[60%]"
|
||||||
:rules="[{ required: true, message: t('apiTestManagement.apiNameRequired') }]"
|
:rules="[{ required: true, message: t('apiTestManagement.apiNameRequired') }]"
|
||||||
>
|
>
|
||||||
<a-input
|
<a-input
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
@change="handleActiveApiChange"
|
@change="handleActiveApiChange"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item :label="t('common.desc')" class="mb-[16px] w-[80%]">
|
<a-form-item :label="t('common.desc')" class="mb-[16px] w-[60%]">
|
||||||
<a-textarea v-model:model-value="requestVModel.description" :max-length="1000" @change="handleActiveApiChange" />
|
<a-textarea v-model:model-value="requestVModel.description" :max-length="1000" @change="handleActiveApiChange" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item :label="t('apiTestManagement.belongModule')" class="mb-[16px] w-[436px]">
|
<a-form-item :label="t('apiTestManagement.belongModule')" class="mb-[16px] w-[436px]">
|
||||||
|
|
|
@ -28,7 +28,11 @@
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</MsEditableTab>
|
</MsEditableTab>
|
||||||
<environmentSelect ref="environmentSelectRef" v-model:current-env="activeApiTab.environmentId" />
|
<environmentSelect
|
||||||
|
ref="environmentSelectRef"
|
||||||
|
v-model:current-env="activeApiTab.environmentId"
|
||||||
|
:set-default-env="false"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<api
|
<api
|
||||||
v-show="(activeApiTab.id === 'all' && currentTab === 'api') || activeApiTab.type === 'api'"
|
v-show="(activeApiTab.id === 'all' && currentTab === 'api') || activeApiTab.type === 'api'"
|
||||||
|
@ -220,14 +224,14 @@
|
||||||
);
|
);
|
||||||
|
|
||||||
// 切换到第一个tab
|
// 切换到第一个tab
|
||||||
function changeActiveApiTabTofirst() {
|
function changeActiveApiTabToFirst() {
|
||||||
activeApiTab.value = apiTabs.value[0] as RequestParam;
|
activeApiTab.value = apiTabs.value[0] as RequestParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 下拉框切换
|
// 下拉框切换
|
||||||
function currentTabChange(val: any) {
|
function currentTabChange(val: any) {
|
||||||
apiTabs.value[0].label = val === 'api' ? t('apiTestManagement.allApi') : t('case.allCase');
|
apiTabs.value[0].label = val === 'api' ? t('apiTestManagement.allApi') : t('case.allCase');
|
||||||
changeActiveApiTabTofirst();
|
changeActiveApiTabToFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
@ -327,7 +331,7 @@
|
||||||
refreshApiTable,
|
refreshApiTable,
|
||||||
handleApiUpdateFromModuleTree,
|
handleApiUpdateFromModuleTree,
|
||||||
handleDeleteApiFromModuleTree,
|
handleDeleteApiFromModuleTree,
|
||||||
changeActiveApiTabTofirst,
|
changeActiveApiTabToFirst,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,7 @@
|
||||||
function handleNodeSelect(keys: string[], _offspringIds: string[]) {
|
function handleNodeSelect(keys: string[], _offspringIds: string[]) {
|
||||||
[activeModule.value] = keys;
|
[activeModule.value] = keys;
|
||||||
offspringIds.value = _offspringIds;
|
offspringIds.value = _offspringIds;
|
||||||
managementRef.value?.changeActiveApiTabTofirst();
|
managementRef.value?.changeActiveApiTabToFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleApiNodeClick(node: ModuleTreeNode) {
|
function handleApiNodeClick(node: ModuleTreeNode) {
|
||||||
|
|
|
@ -34,6 +34,7 @@ export default {
|
||||||
'apiTestManagement.closeOther': 'Close other tabs',
|
'apiTestManagement.closeOther': 'Close other tabs',
|
||||||
'apiTestManagement.showSubdirectory': 'Show subdirectory use case',
|
'apiTestManagement.showSubdirectory': 'Show subdirectory use case',
|
||||||
'apiTestManagement.searchPlaceholder': 'Enter ID/name/api path search',
|
'apiTestManagement.searchPlaceholder': 'Enter ID/name/api path search',
|
||||||
|
'apiTestManagement.searchTaskPlaceholder': 'Enter resource Id/name search',
|
||||||
'apiTestManagement.apiName': 'Api name',
|
'apiTestManagement.apiName': 'Api name',
|
||||||
'apiTestManagement.apiType': 'Api type',
|
'apiTestManagement.apiType': 'Api type',
|
||||||
'apiTestManagement.apiStatus': 'Status',
|
'apiTestManagement.apiStatus': 'Status',
|
||||||
|
|
|
@ -33,6 +33,7 @@ export default {
|
||||||
'apiTestManagement.closeOther': '关闭其他tab',
|
'apiTestManagement.closeOther': '关闭其他tab',
|
||||||
'apiTestManagement.showSubdirectory': '显示子目录用例',
|
'apiTestManagement.showSubdirectory': '显示子目录用例',
|
||||||
'apiTestManagement.searchPlaceholder': '输入 ID/名称/api路径搜索',
|
'apiTestManagement.searchPlaceholder': '输入 ID/名称/api路径搜索',
|
||||||
|
'apiTestManagement.searchTaskPlaceholder': '输入资源ID/名称搜索',
|
||||||
'apiTestManagement.apiName': '接口名称',
|
'apiTestManagement.apiName': '接口名称',
|
||||||
'apiTestManagement.apiType': '请求类型',
|
'apiTestManagement.apiType': '请求类型',
|
||||||
'apiTestManagement.apiStatus': '状态',
|
'apiTestManagement.apiStatus': '状态',
|
||||||
|
|
|
@ -1209,6 +1209,7 @@
|
||||||
requestVModel.value = cloneDeep({
|
requestVModel.value = cloneDeep({
|
||||||
...defaultApiParams,
|
...defaultApiParams,
|
||||||
...props.request,
|
...props.request,
|
||||||
|
name: props.step?.name || props.request.name,
|
||||||
url: props.request.path, // 后台字段是 path
|
url: props.request.path, // 后台字段是 path
|
||||||
activeTab: contentTabList.value[0].value,
|
activeTab: contentTabList.value[0].value,
|
||||||
responseActiveTab: ResponseComposition.BODY,
|
responseActiveTab: ResponseComposition.BODY,
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
:page-size="1"
|
:page-size="1"
|
||||||
:total="props.loopTotal"
|
:total="props.loopTotal"
|
||||||
:show-jumper="props.loopTotal > 5"
|
:show-jumper="props.loopTotal > 5"
|
||||||
:base-size="Infinity"
|
:base-size="0"
|
||||||
show-total
|
show-total
|
||||||
size="mini"
|
size="mini"
|
||||||
class="loop-pagination"
|
class="loop-pagination"
|
||||||
|
|
|
@ -10,11 +10,10 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { WorkbenchRouteEnum } from '@/enums/routeEnum';
|
import { getFirstRouteNameByPermission } from '@/utils/permission';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const back = () => {
|
const back = () => {
|
||||||
// warning: Go to the node that has the permission
|
router.push({ name: getFirstRouteNameByPermission(router.getRoutes()) });
|
||||||
router.push({ name: WorkbenchRouteEnum.WORKBENCH });
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -270,8 +270,8 @@
|
||||||
import { convertToFileByBug } from './utils';
|
import { convertToFileByBug } from './utils';
|
||||||
|
|
||||||
defineOptions({ name: 'BugEditPage' });
|
defineOptions({ name: 'BugEditPage' });
|
||||||
const { setState } = useLeaveUnSaveTip();
|
const { setIsSave } = useLeaveUnSaveTip();
|
||||||
setState(false);
|
setIsSave(false);
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
interface TemplateOption {
|
interface TemplateOption {
|
||||||
|
@ -609,7 +609,7 @@
|
||||||
// 执行保存操作
|
// 执行保存操作
|
||||||
const res = await createOrUpdateBug({ request: tmpObj, fileList: localFiles as unknown as File[] });
|
const res = await createOrUpdateBug({ request: tmpObj, fileList: localFiles as unknown as File[] });
|
||||||
if (isEdit.value) {
|
if (isEdit.value) {
|
||||||
setState(true);
|
setIsSave(true);
|
||||||
Message.success(t('common.updateSuccess'));
|
Message.success(t('common.updateSuccess'));
|
||||||
router.push({
|
router.push({
|
||||||
name: BugManagementRouteEnum.BUG_MANAGEMENT_INDEX,
|
name: BugManagementRouteEnum.BUG_MANAGEMENT_INDEX,
|
||||||
|
@ -617,7 +617,7 @@
|
||||||
} else {
|
} else {
|
||||||
Message.success(t('common.createSuccess'));
|
Message.success(t('common.createSuccess'));
|
||||||
if (isContinue) {
|
if (isContinue) {
|
||||||
setState(false);
|
setIsSave(false);
|
||||||
// 如果是保存并继续创建
|
// 如果是保存并继续创建
|
||||||
const { templateId } = form.value;
|
const { templateId } = form.value;
|
||||||
// 用当前模板初始化自定义字段
|
// 用当前模板初始化自定义字段
|
||||||
|
@ -632,7 +632,7 @@
|
||||||
// 清空文件列表
|
// 清空文件列表
|
||||||
fileList.value = [];
|
fileList.value = [];
|
||||||
} else {
|
} else {
|
||||||
setState(true);
|
setIsSave(true);
|
||||||
// 否则跳转到成功页
|
// 否则跳转到成功页
|
||||||
if (getIsVisited()) {
|
if (getIsVisited()) {
|
||||||
router.push({
|
router.push({
|
||||||
|
@ -831,4 +831,4 @@
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: var(--color-text-4);
|
color: var(--color-text-4);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -49,12 +49,12 @@
|
||||||
|
|
||||||
import Message from '@arco-design/web-vue/es/message';
|
import Message from '@arco-design/web-vue/es/message';
|
||||||
|
|
||||||
const { setState } = useLeaveUnSaveTip();
|
const { setIsSave } = useLeaveUnSaveTip();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
setState(false);
|
setIsSave(false);
|
||||||
|
|
||||||
const featureCaseStore = useFeatureCaseStore();
|
const featureCaseStore = useFeatureCaseStore();
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@
|
||||||
name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE,
|
name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE,
|
||||||
query: { orgId: route.query.orgId, pId: route.query.pId },
|
query: { orgId: route.query.orgId, pId: route.query.pId },
|
||||||
});
|
});
|
||||||
setState(true);
|
setIsSave(true);
|
||||||
// 创建用例
|
// 创建用例
|
||||||
} else {
|
} else {
|
||||||
// 创建并关联
|
// 创建并关联
|
||||||
|
@ -104,7 +104,7 @@
|
||||||
isShowTip.value = !getIsVisited();
|
isShowTip.value = !getIsVisited();
|
||||||
if (isReview) {
|
if (isReview) {
|
||||||
Message.success(t('caseManagement.featureCase.createAndLinkSuccess'));
|
Message.success(t('caseManagement.featureCase.createAndLinkSuccess'));
|
||||||
setState(true);
|
setIsSave(true);
|
||||||
router.back();
|
router.back();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,7 @@
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
setState(true);
|
setIsSave(true);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
|
|
@ -430,7 +430,6 @@
|
||||||
|
|
||||||
async function getFetch() {
|
async function getFetch() {
|
||||||
if (!hasAnyPermission(['FUNCTIONAL_CASE:READ', 'FUNCTIONAL_CASE:READ+UPDATE', 'FUNCTIONAL_CASE:READ+DELETE'])) {
|
if (!hasAnyPermission(['FUNCTIONAL_CASE:READ', 'FUNCTIONAL_CASE:READ+UPDATE', 'FUNCTIONAL_CASE:READ+DELETE'])) {
|
||||||
Message.error(t('common.noPermission'));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (showType.value === 'link') {
|
if (showType.value === 'link') {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<MsCard :min-width="1100" simple has-breadcrumb hide-footer no-content-padding hide-divider show-full-screen>
|
<MsCard :min-width="1100" has-breadcrumb hide-footer no-content-padding hide-divider show-full-screen>
|
||||||
<template #headerLeft>
|
<template #headerLeft>
|
||||||
<a-tooltip :content="reviewDetail.name">
|
<a-tooltip :content="reviewDetail.name">
|
||||||
<div class="one-line-text mr-[8px] max-w-[260px] font-medium text-[var(--color-text-000)]">
|
<div class="one-line-text mr-[8px] max-w-[260px] font-medium text-[var(--color-text-000)]">
|
||||||
|
|
|
@ -147,7 +147,11 @@
|
||||||
</template>
|
</template>
|
||||||
<template v-if="keyword.trim() === ''" #empty>
|
<template v-if="keyword.trim() === ''" #empty>
|
||||||
<div class="flex w-full items-center justify-center p-[8px] text-[var(--color-text-4)]">
|
<div class="flex w-full items-center justify-center p-[8px] text-[var(--color-text-4)]">
|
||||||
{{ t('caseManagement.caseReview.tableNoData') }}
|
{{
|
||||||
|
hasAllPermission(['CASE_REVIEW:READ+ADD'])
|
||||||
|
? t('caseManagement.caseReview.tableNoData')
|
||||||
|
: t('caseManagement.caseReview.tableNoDataNoPermission')
|
||||||
|
}}
|
||||||
<MsButton v-permission="['CASE_REVIEW:READ+ADD']" class="ml-[8px]" @click="() => emit('goCreate')">
|
<MsButton v-permission="['CASE_REVIEW:READ+ADD']" class="ml-[8px]" @click="() => emit('goCreate')">
|
||||||
{{ t('caseManagement.caseReview.create') }}
|
{{ t('caseManagement.caseReview.create') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
|
@ -214,7 +218,7 @@
|
||||||
import useTableStore from '@/hooks/useTableStore';
|
import useTableStore from '@/hooks/useTableStore';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
import useUserStore from '@/store/modules/user';
|
import useUserStore from '@/store/modules/user';
|
||||||
import { hasAnyPermission } from '@/utils/permission';
|
import { hasAllPermission, hasAnyPermission } from '@/utils/permission';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ReviewDetailReviewersItem,
|
ReviewDetailReviewersItem,
|
||||||
|
|
|
@ -6,6 +6,7 @@ export default {
|
||||||
'caseManagement.caseReview.list.searchPlaceholder': 'Search by ID, name, or tag',
|
'caseManagement.caseReview.list.searchPlaceholder': 'Search by ID, name, or tag',
|
||||||
'caseManagement.caseReview.archive': 'Archive',
|
'caseManagement.caseReview.archive': 'Archive',
|
||||||
'caseManagement.caseReview.tableNoData': 'No data yet, please',
|
'caseManagement.caseReview.tableNoData': 'No data yet, please',
|
||||||
|
'caseManagement.caseReview.tableNoDataNoPermission': 'No data yet',
|
||||||
'caseManagement.caseReview.name': 'Review name',
|
'caseManagement.caseReview.name': 'Review name',
|
||||||
'caseManagement.caseReview.creator': 'Creator',
|
'caseManagement.caseReview.creator': 'Creator',
|
||||||
'caseManagement.caseReview.reviewer': 'Reviewer',
|
'caseManagement.caseReview.reviewer': 'Reviewer',
|
||||||
|
|
|
@ -6,6 +6,7 @@ export default {
|
||||||
'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.name': '评审名称',
|
'caseManagement.caseReview.name': '评审名称',
|
||||||
'caseManagement.caseReview.creator': '创建人',
|
'caseManagement.caseReview.creator': '创建人',
|
||||||
'caseManagement.caseReview.reviewer': '评审人',
|
'caseManagement.caseReview.reviewer': '评审人',
|
||||||
|
|
|
@ -33,7 +33,11 @@
|
||||||
v-model="userInfo.username"
|
v-model="userInfo.username"
|
||||||
:max-length="64"
|
:max-length="64"
|
||||||
size="large"
|
size="large"
|
||||||
:placeholder="t('login.form.userName.placeholder')"
|
:placeholder="
|
||||||
|
userInfo.authenticate !== 'LOCAL'
|
||||||
|
? t('login.form.userName.placeholderOther')
|
||||||
|
: t('login.form.userName.placeholder')
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
|
@ -91,6 +95,7 @@
|
||||||
import useLoading from '@/hooks/useLoading';
|
import useLoading from '@/hooks/useLoading';
|
||||||
import { NO_PROJECT_ROUTE_NAME, NO_RESOURCE_ROUTE_NAME } from '@/router/constants';
|
import { NO_PROJECT_ROUTE_NAME, NO_RESOURCE_ROUTE_NAME } from '@/router/constants';
|
||||||
import { useAppStore, useUserStore } from '@/store';
|
import { useAppStore, useUserStore } from '@/store';
|
||||||
|
import useLicenseStore from '@/store/modules/setting/license';
|
||||||
import { encrypted } from '@/utils';
|
import { encrypted } from '@/utils';
|
||||||
import { setLoginExpires } from '@/utils/auth';
|
import { setLoginExpires } from '@/utils/auth';
|
||||||
import { getFirstRouteNameByPermission, routerNameHasPermission } from '@/utils/permission';
|
import { getFirstRouteNameByPermission, routerNameHasPermission } from '@/utils/permission';
|
||||||
|
@ -103,6 +108,7 @@
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
|
const licenseStore = useLicenseStore();
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
isPreview?: boolean;
|
isPreview?: boolean;
|
||||||
|
@ -181,7 +187,7 @@
|
||||||
![NO_RESOURCE_ROUTE_NAME, NO_PROJECT_ROUTE_NAME].includes(redirect as string) &&
|
![NO_RESOURCE_ROUTE_NAME, NO_PROJECT_ROUTE_NAME].includes(redirect as string) &&
|
||||||
routerNameHasPermission(redirect as string, router.getRoutes());
|
routerNameHasPermission(redirect as string, router.getRoutes());
|
||||||
const currentRouteName = getFirstRouteNameByPermission(router.getRoutes());
|
const currentRouteName = getFirstRouteNameByPermission(router.getRoutes());
|
||||||
const res = await getProjectInfo(appStore.currentProjectId);
|
const [res] = await Promise.all([getProjectInfo(appStore.currentProjectId), licenseStore.getValidateLicense()]); // 登录前校验 license 避免进入页面后无license状态
|
||||||
if (!res || res.deleted) {
|
if (!res || res.deleted) {
|
||||||
router.push({
|
router.push({
|
||||||
name: NO_PROJECT_ROUTE_NAME,
|
name: NO_PROJECT_ROUTE_NAME,
|
||||||
|
|
|
@ -4,8 +4,9 @@ export default {
|
||||||
'login.form.password.errMsg': 'Password cannot be empty',
|
'login.form.password.errMsg': 'Password cannot be empty',
|
||||||
'login.form.login.errMsg': 'Login error, refresh and try again',
|
'login.form.login.errMsg': 'Login error, refresh and try again',
|
||||||
'login.form.login.success': 'welcome to use',
|
'login.form.login.success': 'welcome to use',
|
||||||
'login.form.userName.placeholder': 'Username',
|
'login.form.userName.placeholder': 'Please enter your email',
|
||||||
'login.form.password.placeholder': 'Password',
|
'login.form.userName.placeholderOther': 'Please enter your account',
|
||||||
|
'login.form.password.placeholder': 'Please enter your password',
|
||||||
'login.form.rememberPassword': 'Remember password',
|
'login.form.rememberPassword': 'Remember password',
|
||||||
'login.form.forgetPassword': 'Forgot password',
|
'login.form.forgetPassword': 'Forgot password',
|
||||||
'login.form.login': 'login',
|
'login.form.login': 'login',
|
||||||
|
|
|
@ -5,7 +5,8 @@ export default {
|
||||||
'login.form.login.errMsg': '登录出错,请刷新重试',
|
'login.form.login.errMsg': '登录出错,请刷新重试',
|
||||||
'login.form.login.success': '欢迎使用',
|
'login.form.login.success': '欢迎使用',
|
||||||
'login.form.userName.placeholder': '请输入邮箱登录',
|
'login.form.userName.placeholder': '请输入邮箱登录',
|
||||||
'login.form.password.placeholder': '密码',
|
'login.form.userName.placeholderOther': '请输入账号登录',
|
||||||
|
'login.form.password.placeholder': '请输入密码',
|
||||||
'login.form.rememberPassword': '记住密码',
|
'login.form.rememberPassword': '记住密码',
|
||||||
'login.form.forgetPassword': '忘记密码',
|
'login.form.forgetPassword': '忘记密码',
|
||||||
'login.form.login': '登录',
|
'login.form.login': '登录',
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
|
||||||
import AllPrams from './allParams/index.vue';
|
|
||||||
import RequestHeader from './requestHeader/index.vue';
|
import RequestHeader from './requestHeader/index.vue';
|
||||||
|
|
||||||
import { updateOrAddGlobalParam } from '@/api/modules/project-management/envManagement';
|
import { updateOrAddGlobalParam } from '@/api/modules/project-management/envManagement';
|
||||||
|
@ -38,8 +37,8 @@
|
||||||
const headerParams = ref<EnvConfigItem[]>([]);
|
const headerParams = ref<EnvConfigItem[]>([]);
|
||||||
const GlobalVariable = ref<EnvConfigItem[]>([]);
|
const GlobalVariable = ref<EnvConfigItem[]>([]);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { setState } = useLeaveUnSaveTip();
|
const { setIsSave } = useLeaveUnSaveTip();
|
||||||
setState(true);
|
setIsSave(true);
|
||||||
const canSave = ref(false);
|
const canSave = ref(false);
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
@ -64,7 +63,7 @@
|
||||||
|
|
||||||
function change() {
|
function change() {
|
||||||
canSave.value = true;
|
canSave.value = true;
|
||||||
setState(false);
|
setIsSave(false);
|
||||||
}
|
}
|
||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
try {
|
try {
|
||||||
|
@ -85,7 +84,7 @@
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
await updateOrAddGlobalParam(params);
|
await updateOrAddGlobalParam(params);
|
||||||
setState(true);
|
setIsSave(true);
|
||||||
Message.success(t('common.saveSuccess'));
|
Message.success(t('common.saveSuccess'));
|
||||||
canSave.value = false;
|
canSave.value = false;
|
||||||
initEnvDetail();
|
initEnvDetail();
|
||||||
|
|
|
@ -101,8 +101,8 @@
|
||||||
import { defaultHeaderParamsItem } from '@/views/api-test/components/config';
|
import { defaultHeaderParamsItem } from '@/views/api-test/components/config';
|
||||||
import { filterKeyValParams } from '@/views/api-test/components/utils';
|
import { filterKeyValParams } from '@/views/api-test/components/utils';
|
||||||
|
|
||||||
const { setState } = useLeaveUnSaveTip();
|
const { setIsSave } = useLeaveUnSaveTip();
|
||||||
setState(false);
|
setIsSave(false);
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'ok', envId: string | undefined): void;
|
(e: 'ok', envId: string | undefined): void;
|
||||||
(e: 'resetEnv'): void;
|
(e: 'resetEnv'): void;
|
||||||
|
@ -231,7 +231,7 @@
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
store.currentEnvDetailInfo.mock = true;
|
store.currentEnvDetailInfo.mock = true;
|
||||||
await updateOrAddEnv({ fileList: [], request: getParameters() });
|
await updateOrAddEnv({ fileList: [], request: getParameters() });
|
||||||
setState(true);
|
setIsSave(true);
|
||||||
|
|
||||||
Message.success(store.currentEnvDetailInfo.id ? t('common.updateSuccess') : t('common.saveSuccess'));
|
Message.success(store.currentEnvDetailInfo.id ? t('common.updateSuccess') : t('common.saveSuccess'));
|
||||||
emit('ok', store.currentEnvDetailInfo.id);
|
emit('ok', store.currentEnvDetailInfo.id);
|
||||||
|
@ -331,4 +331,4 @@
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -284,7 +284,7 @@
|
||||||
NEW_ENV_PARAM,
|
NEW_ENV_PARAM,
|
||||||
} from '@/store/modules/setting/useProjectEnvStore';
|
} from '@/store/modules/setting/useProjectEnvStore';
|
||||||
import { downloadByteFile } from '@/utils';
|
import { downloadByteFile } from '@/utils';
|
||||||
import { hasAllPermission, hasAnyPermission } from '@/utils/permission';
|
import { hasAnyPermission } from '@/utils/permission';
|
||||||
|
|
||||||
import { EnvListItem, PopVisible } from '@/models/projectManagement/environmental';
|
import { EnvListItem, PopVisible } from '@/models/projectManagement/environmental';
|
||||||
import { EnvAuthScopeEnum, EnvAuthTypeEnum } from '@/enums/envEnum';
|
import { EnvAuthScopeEnum, EnvAuthTypeEnum } from '@/enums/envEnum';
|
||||||
|
@ -293,8 +293,8 @@
|
||||||
|
|
||||||
const { openModal } = useModal();
|
const { openModal } = useModal();
|
||||||
|
|
||||||
const { setState } = useLeaveUnSaveTip();
|
const { setIsSave } = useLeaveUnSaveTip();
|
||||||
setState(false);
|
setIsSave(false);
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const store = useProjectEnvStore();
|
const store = useProjectEnvStore();
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
<a-input
|
<a-input
|
||||||
v-else
|
v-else
|
||||||
v-model:model-value="form.field"
|
v-model:model-value="form.field"
|
||||||
:max-length="props.fieldConfig?.maxLength || 50"
|
:max-length="props.fieldConfig?.maxLength || 255"
|
||||||
:placeholder="props.fieldConfig?.placeholder || t('project.fileManagement.namePlaceholder')"
|
:placeholder="props.fieldConfig?.placeholder || t('project.fileManagement.namePlaceholder')"
|
||||||
class="w-[245px]"
|
class="w-[245px]"
|
||||||
@press-enter="beforeConfirm(undefined)"
|
@press-enter="beforeConfirm(undefined)"
|
||||||
|
|
|
@ -670,7 +670,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasAuth) {
|
if (!hasAuth) {
|
||||||
Message.error(t('common.noPermission'));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -773,7 +772,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasAuth) {
|
if (!hasAuth) {
|
||||||
Message.error(t('common.noPermission'));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await postUpdateMenu(
|
await postUpdateMenu(
|
||||||
|
|
|
@ -267,9 +267,9 @@
|
||||||
const currentOrgId = computed(() => appStore.currentOrgId);
|
const currentOrgId = computed(() => appStore.currentOrgId);
|
||||||
const currentProjectId = computed(() => appStore.currentProjectId);
|
const currentProjectId = computed(() => appStore.currentProjectId);
|
||||||
|
|
||||||
const { setState } = useLeaveUnSaveTip();
|
const { setIsSave } = useLeaveUnSaveTip();
|
||||||
|
|
||||||
setState(false);
|
setIsSave(false);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -405,7 +405,7 @@
|
||||||
router.push({ name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT, query: route.query });
|
router.push({ name: ProjectManagementRouteEnum.PROJECT_MANAGEMENT_TEMPLATE_MANAGEMENT, query: route.query });
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(true);
|
setIsSave(true);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
@ -834,7 +834,6 @@
|
||||||
background: var(--color-text-n9);
|
background: var(--color-text-n9);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.arco-form-item-layout-vertical > .arco-form-item-label-col) {
|
:deep(.arco-form-item-layout-vertical > .arco-form-item-label-col) {
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,7 +150,7 @@
|
||||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||||
import type { FormItemType } from '@/components/pure/ms-form-create/types';
|
import type { FormItemType } from '@/components/pure/ms-form-create/types';
|
||||||
import MsBatchForm from '@/components/business/ms-batch-form/index.vue';
|
import MsBatchForm from '@/components/business/ms-batch-form/index.vue';
|
||||||
import type { FormItemModel, MsBatchFormInstance } from '@/components/business/ms-batch-form/types';
|
import type { FormItemModel } from '@/components/business/ms-batch-form/types';
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import { useAppStore } from '@/store';
|
import { useAppStore } from '@/store';
|
||||||
|
@ -252,7 +252,7 @@
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
const optionsModels: Ref<FormItemModel[]> = ref([]);
|
const optionsModels: Ref<FormItemModel[]> = ref([]);
|
||||||
const batchFormRef = ref<MsBatchFormInstance | null>(null);
|
const batchFormRef = ref<InstanceType<typeof MsBatchForm>>();
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
fieldForm.value = { ...initFieldForm };
|
fieldForm.value = { ...initFieldForm };
|
||||||
|
|
|
@ -5,6 +5,15 @@
|
||||||
<a-button v-permission="['SYSTEM_PARAMETER_SETTING_AUTH:READ+ADD']" type="primary" @click="createAuth">
|
<a-button v-permission="['SYSTEM_PARAMETER_SETTING_AUTH:READ+ADD']" type="primary" @click="createAuth">
|
||||||
{{ t('system.config.auth.add') }}
|
{{ t('system.config.auth.add') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
|
<a-input-search
|
||||||
|
v-model:model-value="keyword"
|
||||||
|
:placeholder="t('system.config.auth.searchTip')"
|
||||||
|
class="w-[230px]"
|
||||||
|
allow-clear
|
||||||
|
@search="searchAuth"
|
||||||
|
@press-enter="searchAuth"
|
||||||
|
@clear="searchAuth"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<ms-base-table v-bind="propsRes" no-disable v-on="propsEvent">
|
<ms-base-table v-bind="propsRes" no-disable v-on="propsEvent">
|
||||||
<template #name="{ record }">
|
<template #name="{ record }">
|
||||||
|
@ -684,7 +693,7 @@
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const tableStore = useTableStore();
|
const tableStore = useTableStore();
|
||||||
const { propsRes, propsEvent, loadList } = useTable(getAuthList, {
|
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(getAuthList, {
|
||||||
tableKey: TableKeyEnum.SYSTEM_AUTH,
|
tableKey: TableKeyEnum.SYSTEM_AUTH,
|
||||||
columns,
|
columns,
|
||||||
scroll: { y: 'auto' },
|
scroll: { y: 'auto' },
|
||||||
|
@ -696,6 +705,15 @@
|
||||||
loadList();
|
loadList();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const keyword = ref('');
|
||||||
|
|
||||||
|
function searchAuth() {
|
||||||
|
setLoadListParams({
|
||||||
|
keyword: keyword.value,
|
||||||
|
});
|
||||||
|
loadList();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 启用认证源
|
* 启用认证源
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -50,10 +50,10 @@
|
||||||
<div :class="['config-preview', currentLocale === 'en-US' ? 'config-preview--en' : '']">
|
<div :class="['config-preview', currentLocale === 'en-US' ? 'config-preview--en' : '']">
|
||||||
<div ref="loginPageFullRef" class="login-preview">
|
<div ref="loginPageFullRef" class="login-preview">
|
||||||
<div :class="['config-preview-head', isLoginPageFullscreen ? 'full-preview-head' : '']">
|
<div :class="['config-preview-head', isLoginPageFullscreen ? 'full-preview-head' : '']">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between overflow-hidden">
|
||||||
<img v-if="pageConfig.icon[0]?.url" :src="pageConfig.icon[0].url" class="h-[18px] w-[18px]" />
|
<img v-if="pageConfig.icon[0]?.url" :src="pageConfig.icon[0].url" class="h-[18px] w-[18px]" />
|
||||||
<svg-icon v-else name="logo" class="h-[18px] w-[18px]"></svg-icon>
|
<svg-icon v-else name="logo" class="h-[18px] w-[18px]"></svg-icon>
|
||||||
<div class="ml-[4px] text-[10px]">{{ pageConfig.title }}</div>
|
<div class="one-line-text ml-[4px] text-[10px]">{{ pageConfig.title }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="w-[96px] cursor-pointer text-right !text-[var(--color-text-4)]"
|
class="w-[96px] cursor-pointer text-right !text-[var(--color-text-4)]"
|
||||||
|
|
|
@ -96,6 +96,7 @@ export default {
|
||||||
'system.config.page.unsave': 'Unsaved',
|
'system.config.page.unsave': 'Unsaved',
|
||||||
'system.config.page.saveSuccess': 'Saved successfully',
|
'system.config.page.saveSuccess': 'Saved successfully',
|
||||||
'system.config.auth.add': 'Add authentication',
|
'system.config.auth.add': 'Add authentication',
|
||||||
|
'system.config.auth.searchTip': 'Search by name',
|
||||||
'system.config.auth.enable': 'Enable',
|
'system.config.auth.enable': 'Enable',
|
||||||
'system.config.auth.enableSuccess': 'Enabled successfully',
|
'system.config.auth.enableSuccess': 'Enabled successfully',
|
||||||
'system.config.auth.enableTipTitle': 'Enable authentication {name}',
|
'system.config.auth.enableTipTitle': 'Enable authentication {name}',
|
||||||
|
|
|
@ -92,6 +92,7 @@ export default {
|
||||||
'system.config.page.unsave': '未保存',
|
'system.config.page.unsave': '未保存',
|
||||||
'system.config.page.saveSuccess': '保存成功',
|
'system.config.page.saveSuccess': '保存成功',
|
||||||
'system.config.auth.add': '添加认证',
|
'system.config.auth.add': '添加认证',
|
||||||
|
'system.config.auth.searchTip': '输入名称搜索',
|
||||||
'system.config.auth.enable': '启用',
|
'system.config.auth.enable': '启用',
|
||||||
'system.config.auth.enableSuccess': '启用成功',
|
'system.config.auth.enableSuccess': '启用成功',
|
||||||
'system.config.auth.enableTipTitle': '启用认证 {name}',
|
'system.config.auth.enableTipTitle': '启用认证 {name}',
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:title="title"
|
:title="title"
|
||||||
:is-edit="isEdit"
|
:is-edit="isEdit"
|
||||||
|
:save-text="t('system.resourcePool.add')"
|
||||||
|
:save-and-continue-text="t('system.resourcePool.addAndContinue')"
|
||||||
|
:handle-back="handleBack"
|
||||||
has-breadcrumb
|
has-breadcrumb
|
||||||
@save="beforeSave"
|
@save="beforeSave"
|
||||||
@save-and-continue="beforeSave(true)"
|
@save-and-continue="beforeSave(true)"
|
||||||
|
@ -19,6 +22,7 @@
|
||||||
v-model:model-value="form.name"
|
v-model:model-value="form.name"
|
||||||
:placeholder="t('system.resourcePool.namePlaceholder')"
|
:placeholder="t('system.resourcePool.namePlaceholder')"
|
||||||
:max-length="255"
|
:max-length="255"
|
||||||
|
@change="() => setIsSave(false)"
|
||||||
></a-input>
|
></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item :label="t('system.resourcePool.desc')" field="description" class="form-item">
|
<a-form-item :label="t('system.resourcePool.desc')" field="description" class="form-item">
|
||||||
|
@ -26,6 +30,7 @@
|
||||||
v-model:model-value="form.description"
|
v-model:model-value="form.description"
|
||||||
:placeholder="t('system.resourcePool.descPlaceholder')"
|
:placeholder="t('system.resourcePool.descPlaceholder')"
|
||||||
:max-length="1000"
|
:max-length="1000"
|
||||||
|
@change="() => setIsSave(false)"
|
||||||
></a-textarea>
|
></a-textarea>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item :label="t('system.resourcePool.serverUrl')" field="serverUrl" class="form-item">
|
<a-form-item :label="t('system.resourcePool.serverUrl')" field="serverUrl" class="form-item">
|
||||||
|
@ -33,10 +38,11 @@
|
||||||
v-model:model-value="form.serverUrl"
|
v-model:model-value="form.serverUrl"
|
||||||
:placeholder="t('system.resourcePool.rootUrlPlaceholder')"
|
:placeholder="t('system.resourcePool.rootUrlPlaceholder')"
|
||||||
:max-length="255"
|
:max-length="255"
|
||||||
|
@change="() => setIsSave(false)"
|
||||||
></a-input>
|
></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item :label="t('system.resourcePool.orgRange')" field="orgType" class="form-item">
|
<a-form-item :label="t('system.resourcePool.orgRange')" field="orgType" class="form-item">
|
||||||
<a-radio-group v-model:model-value="form.orgType">
|
<a-radio-group v-model:model-value="form.orgType" @change="() => setIsSave(false)">
|
||||||
<a-radio value="allOrg">
|
<a-radio value="allOrg">
|
||||||
{{ t('system.resourcePool.orgAll') }}
|
{{ t('system.resourcePool.orgAll') }}
|
||||||
<a-tooltip :content="t('system.resourcePool.orgRangeTip')" position="top" mini>
|
<a-tooltip :content="t('system.resourcePool.orgRangeTip')" position="top" mini>
|
||||||
|
@ -59,6 +65,7 @@
|
||||||
:placeholder="t('system.resourcePool.orgPlaceholder')"
|
:placeholder="t('system.resourcePool.orgPlaceholder')"
|
||||||
multiple
|
multiple
|
||||||
allow-clear
|
allow-clear
|
||||||
|
@change="() => setIsSave(false)"
|
||||||
>
|
>
|
||||||
<a-option v-for="org of orgOptions" :key="org.id" :value="org.id">{{ org.name }}</a-option>
|
<a-option v-for="org of orgOptions" :key="org.id" :value="org.id">{{ org.name }}</a-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
|
@ -70,7 +77,7 @@
|
||||||
:rules="[{ required: true, message: t('system.resourcePool.useRequired') }]"
|
:rules="[{ required: true, message: t('system.resourcePool.useRequired') }]"
|
||||||
asterisk-position="end"
|
asterisk-position="end"
|
||||||
>
|
>
|
||||||
<a-checkbox-group v-model:model-value="form.use">
|
<a-checkbox-group v-model:model-value="form.use" @change="() => setIsSave(false)">
|
||||||
<a-checkbox v-for="use of useList" :key="use.value" :value="use.value">{{ t(use.label) }}</a-checkbox>
|
<a-checkbox v-for="use of useList" :key="use.value" :value="use.value">{{ t(use.label) }}</a-checkbox>
|
||||||
</a-checkbox-group>
|
</a-checkbox-group>
|
||||||
<MsFormItemSub
|
<MsFormItemSub
|
||||||
|
@ -191,6 +198,7 @@
|
||||||
:default-vals="defaultVals"
|
:default-vals="defaultVals"
|
||||||
:hide-add="!isXpack"
|
:hide-add="!isXpack"
|
||||||
max-height="250px"
|
max-height="250px"
|
||||||
|
@change="() => setIsSave(false)"
|
||||||
></MsBatchForm>
|
></MsBatchForm>
|
||||||
<!-- TODO:代码编辑器懒加载 -->
|
<!-- TODO:代码编辑器懒加载 -->
|
||||||
<div v-show="form.addType === 'multiple'">
|
<div v-show="form.addType === 'multiple'">
|
||||||
|
@ -200,6 +208,7 @@
|
||||||
height="400px"
|
height="400px"
|
||||||
theme="MS-text"
|
theme="MS-text"
|
||||||
:show-theme-change="false"
|
:show-theme-change="false"
|
||||||
|
@change="() => setIsSave(false)"
|
||||||
>
|
>
|
||||||
<template #leftTitle>
|
<template #leftTitle>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
|
@ -228,6 +237,7 @@
|
||||||
v-model:model-value="form.testResourceDTO.ip"
|
v-model:model-value="form.testResourceDTO.ip"
|
||||||
:placeholder="t('system.resourcePool.testResourceDTO.ipPlaceholder')"
|
:placeholder="t('system.resourcePool.testResourceDTO.ipPlaceholder')"
|
||||||
:max-length="255"
|
:max-length="255"
|
||||||
|
@change="() => setIsSave(false)"
|
||||||
></a-input>
|
></a-input>
|
||||||
<div class="mt-[4px] text-[12px] leading-[16px] text-[var(--color-text-4)]">
|
<div class="mt-[4px] text-[12px] leading-[16px] text-[var(--color-text-4)]">
|
||||||
{{ t('system.resourcePool.testResourceDTO.ipSubTip', { ip: '100.0.0.100', domain: 'example.com' }) }}
|
{{ t('system.resourcePool.testResourceDTO.ipSubTip', { ip: '100.0.0.100', domain: 'example.com' }) }}
|
||||||
|
@ -245,6 +255,7 @@
|
||||||
:placeholder="t('system.resourcePool.testResourceDTO.tokenPlaceholder')"
|
:placeholder="t('system.resourcePool.testResourceDTO.tokenPlaceholder')"
|
||||||
:max-length="1500"
|
:max-length="1500"
|
||||||
autocomplete="new-password"
|
autocomplete="new-password"
|
||||||
|
@change="() => setIsSave(false)"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
|
@ -259,6 +270,7 @@
|
||||||
:placeholder="t('system.resourcePool.testResourceDTO.nameSpacesPlaceholder')"
|
:placeholder="t('system.resourcePool.testResourceDTO.nameSpacesPlaceholder')"
|
||||||
:max-length="255"
|
:max-length="255"
|
||||||
class="mr-[8px] flex-1"
|
class="mr-[8px] flex-1"
|
||||||
|
@change="() => setIsSave(false)"
|
||||||
></a-input>
|
></a-input>
|
||||||
<a-tooltip
|
<a-tooltip
|
||||||
:content="t('system.resourcePool.testResourceDTO.downloadRoleYamlTip')"
|
:content="t('system.resourcePool.testResourceDTO.downloadRoleYamlTip')"
|
||||||
|
@ -284,6 +296,7 @@
|
||||||
:placeholder="t('system.resourcePool.testResourceDTO.deployNamePlaceholder')"
|
:placeholder="t('system.resourcePool.testResourceDTO.deployNamePlaceholder')"
|
||||||
:max-length="255"
|
:max-length="255"
|
||||||
class="mr-[8px] flex-1"
|
class="mr-[8px] flex-1"
|
||||||
|
@change="() => setIsSave(false)"
|
||||||
></a-input>
|
></a-input>
|
||||||
<a-tooltip
|
<a-tooltip
|
||||||
:content="t('system.resourcePool.testResourceDTO.downloadDeployYamlTip')"
|
:content="t('system.resourcePool.testResourceDTO.downloadDeployYamlTip')"
|
||||||
|
@ -314,6 +327,8 @@
|
||||||
:step="1"
|
:step="1"
|
||||||
mode="button"
|
mode="button"
|
||||||
class="w-[160px]"
|
class="w-[160px]"
|
||||||
|
model-event="input"
|
||||||
|
@change="() => setIsSave(false)"
|
||||||
></a-input-number>
|
></a-input-number>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
|
@ -328,6 +343,8 @@
|
||||||
:step="1"
|
:step="1"
|
||||||
mode="button"
|
mode="button"
|
||||||
class="w-[160px]"
|
class="w-[160px]"
|
||||||
|
model-event="input"
|
||||||
|
@change="() => setIsSave(false)"
|
||||||
></a-input-number>
|
></a-input-number>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</template>
|
</template>
|
||||||
|
@ -351,19 +368,20 @@
|
||||||
import { computed, onBeforeMount, Ref, ref, watch, watchEffect } from 'vue';
|
import { computed, onBeforeMount, Ref, ref, watch, watchEffect } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { FormInstance, Message, SelectOptionData } from '@arco-design/web-vue';
|
import { FormInstance, Message, SelectOptionData } from '@arco-design/web-vue';
|
||||||
import { isEmpty } from 'lodash-es';
|
import { cloneDeep, isEmpty } from 'lodash-es';
|
||||||
|
|
||||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||||
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
|
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
|
||||||
import MsBatchForm from '@/components/business/ms-batch-form/index.vue';
|
import MsBatchForm from '@/components/business/ms-batch-form/index.vue';
|
||||||
import type { FormItemModel, MsBatchFormInstance } from '@/components/business/ms-batch-form/types';
|
import type { FormItemModel } from '@/components/business/ms-batch-form/types';
|
||||||
import MsFormItemSub from '@/components/business/ms-form-item-sub/index.vue';
|
import MsFormItemSub from '@/components/business/ms-form-item-sub/index.vue';
|
||||||
import JobTemplateDrawer from './components/jobTemplateDrawer.vue';
|
import JobTemplateDrawer from './components/jobTemplateDrawer.vue';
|
||||||
|
|
||||||
import { getSystemOrgOption } from '@/api/modules/setting/organizationAndProject';
|
import { getSystemOrgOption } from '@/api/modules/setting/organizationAndProject';
|
||||||
import { addPool, getPoolInfo, updatePoolInfo } from '@/api/modules/setting/resourcePool';
|
import { addPool, getPoolInfo, updatePoolInfo } from '@/api/modules/setting/resourcePool';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
import useLeaveUnSaveTip from '@/hooks/useLeaveUnSaveTip';
|
||||||
import useVisit from '@/hooks/useVisit';
|
import useVisit from '@/hooks/useVisit';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
import useLicenseStore from '@/store/modules/setting/license';
|
import useLicenseStore from '@/store/modules/setting/license';
|
||||||
|
@ -371,6 +389,7 @@
|
||||||
import { scrollIntoView } from '@/utils/dom';
|
import { scrollIntoView } from '@/utils/dom';
|
||||||
|
|
||||||
import type { NodesListItem, UpdateResourcePoolParams } from '@/models/setting/resourcePool';
|
import type { NodesListItem, UpdateResourcePoolParams } from '@/models/setting/resourcePool';
|
||||||
|
import { SettingRouteEnum } from '@/enums/routeEnum';
|
||||||
|
|
||||||
import { getYaml, job, YamlType } from './template';
|
import { getYaml, job, YamlType } from './template';
|
||||||
|
|
||||||
|
@ -380,6 +399,7 @@
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
|
const { setIsSave } = useLeaveUnSaveTip();
|
||||||
|
|
||||||
const title = ref('');
|
const title = ref('');
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
@ -390,7 +410,7 @@
|
||||||
description: '',
|
description: '',
|
||||||
serverUrl: '',
|
serverUrl: '',
|
||||||
orgType: 'allOrg',
|
orgType: 'allOrg',
|
||||||
use: ['performance', 'API'],
|
use: ['API'],
|
||||||
type: 'Node',
|
type: 'Node',
|
||||||
addType: 'single',
|
addType: 'single',
|
||||||
testResourceDTO: {
|
testResourceDTO: {
|
||||||
|
@ -409,7 +429,7 @@
|
||||||
orgIds: [] as string[],
|
orgIds: [] as string[],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const form = ref({ ...defaultForm });
|
const form = ref({ ...cloneDeep(defaultForm) });
|
||||||
const formRef = ref<FormInstance | null>(null);
|
const formRef = ref<FormInstance | null>(null);
|
||||||
const orgOptions = ref<SelectOptionData>([]);
|
const orgOptions = ref<SelectOptionData>([]);
|
||||||
// TODO:第一版只有接口测试
|
// TODO:第一版只有接口测试
|
||||||
|
@ -427,7 +447,7 @@
|
||||||
// value: 'UI',
|
// value: 'UI',
|
||||||
// },
|
// },
|
||||||
]);
|
]);
|
||||||
const defaultGrid = 'http://selenium-hub:4444';
|
// const defaultGrid = 'http://selenium-hub:4444';
|
||||||
const maxConcurrentNumber = computed(() => {
|
const maxConcurrentNumber = computed(() => {
|
||||||
if (isXpack.value) {
|
if (isXpack.value) {
|
||||||
return 9999999;
|
return 9999999;
|
||||||
|
@ -482,10 +502,10 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultHeap = '-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m';
|
// const defaultHeap = '-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m';
|
||||||
function fillHeapByDefault() {
|
// function fillHeapByDefault() {
|
||||||
form.value.testResourceDTO.loadTestHeap = defaultHeap;
|
// form.value.testResourceDTO.loadTestHeap = defaultHeap;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const visitedKey = 'changeAddResourceType';
|
const visitedKey = 'changeAddResourceType';
|
||||||
const { addVisited, getIsVisited } = useVisit(visitedKey);
|
const { addVisited, getIsVisited } = useVisit(visitedKey);
|
||||||
|
@ -534,7 +554,7 @@
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const batchFormRef = ref<MsBatchFormInstance | null>(null);
|
const batchFormRef = ref<InstanceType<typeof MsBatchForm>>();
|
||||||
const batchFormModels: Ref<FormItemModel[]> = ref([
|
const batchFormModels: Ref<FormItemModel[]> = ref([
|
||||||
{
|
{
|
||||||
filed: 'ip',
|
filed: 'ip',
|
||||||
|
@ -580,7 +600,7 @@
|
||||||
// 动态表单默认值
|
// 动态表单默认值
|
||||||
const defaultVals = computed(() => {
|
const defaultVals = computed(() => {
|
||||||
const { nodesList } = form.value.testResourceDTO;
|
const { nodesList } = form.value.testResourceDTO;
|
||||||
return nodesList.map((node) => node);
|
return nodesList.map((node) => cloneDeep(node));
|
||||||
});
|
});
|
||||||
|
|
||||||
// 代码编辑器内容
|
// 代码编辑器内容
|
||||||
|
@ -606,9 +626,9 @@
|
||||||
* 提取动态表单项输入的内容
|
* 提取动态表单项输入的内容
|
||||||
*/
|
*/
|
||||||
function setBatchFormRes() {
|
function setBatchFormRes() {
|
||||||
const res = batchFormRef.value?.getFormResult<NodesListItem>();
|
const res = batchFormRef.value?.getFormResult();
|
||||||
if (res?.length) {
|
if (res?.length) {
|
||||||
form.value.testResourceDTO.nodesList = res.map((e) => e);
|
form.value.testResourceDTO.nodesList = res.map((e) => e) as NodesListItem[];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -652,12 +672,14 @@
|
||||||
// 从单个添加切换到批量添加,需要先提取组件的输入框内容
|
// 从单个添加切换到批量添加,需要先提取组件的输入框内容
|
||||||
setBatchFormRes();
|
setBatchFormRes();
|
||||||
}
|
}
|
||||||
|
setIsSave(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeResourceType(val: string | number | boolean) {
|
function changeResourceType(val: string | number | boolean) {
|
||||||
if (val === 'Kubernetes') {
|
if (val === 'Kubernetes') {
|
||||||
setBatchFormRes();
|
setBatchFormRes();
|
||||||
}
|
}
|
||||||
|
setIsSave(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -699,7 +721,7 @@
|
||||||
* 重置表单信息
|
* 重置表单信息
|
||||||
*/
|
*/
|
||||||
function resetForm() {
|
function resetForm() {
|
||||||
form.value = { ...defaultForm };
|
form.value = { ...cloneDeep(defaultForm) };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -841,6 +863,10 @@
|
||||||
return scrollIntoView(document.querySelector('.arco-form-item-message'), { block: 'center' });
|
return scrollIntoView(document.querySelector('.arco-form-item-message'), { block: 'center' });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleBack() {
|
||||||
|
router.replace({ name: SettingRouteEnum.SETTING_SYSTEM_RESOURCE_POOL });
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|
|
@ -287,6 +287,12 @@
|
||||||
try {
|
try {
|
||||||
const res = await getPoolInfo(id);
|
const res = await getPoolInfo(id);
|
||||||
if (res) {
|
if (res) {
|
||||||
|
if (res.deleted) {
|
||||||
|
Message.warning(t('common.resourceDeleted'));
|
||||||
|
drawerLoading.value = false;
|
||||||
|
showDetailDrawer.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
activePool.value = res;
|
activePool.value = res;
|
||||||
const poolUses = [
|
const poolUses = [
|
||||||
activePool.value.apiTest ? t('system.resourcePool.useAPI') : '',
|
activePool.value.apiTest ? t('system.resourcePool.useAPI') : '',
|
||||||
|
|
|
@ -20,14 +20,14 @@ export default {
|
||||||
'system.resourcePool.disablePoolSuccess': 'Disabled successfully',
|
'system.resourcePool.disablePoolSuccess': 'Disabled successfully',
|
||||||
'system.resourcePool.deletePoolTip': 'Are you sure to delete the `{name}` resource?',
|
'system.resourcePool.deletePoolTip': 'Are you sure to delete the `{name}` resource?',
|
||||||
'system.resourcePool.deletePoolContentUsed':
|
'system.resourcePool.deletePoolContentUsed':
|
||||||
'This resource pool has been used, and related tests will stop immediately after deletion, please operate with caution!',
|
'If this resource pool has been used, and related tests will stop immediately after deletion, please operate with caution!',
|
||||||
'system.resourcePool.deletePoolContentUnuse': 'This resource pool is not in use. Are you sure to delete it?',
|
'system.resourcePool.deletePoolContentUnuse': 'This resource pool is not in use. Are you sure to delete it?',
|
||||||
'system.resourcePool.deletePoolConfirm': 'Confirm',
|
'system.resourcePool.deletePoolConfirm': 'Confirm',
|
||||||
'system.resourcePool.deletePoolCancel': 'Cancel',
|
'system.resourcePool.deletePoolCancel': 'Cancel',
|
||||||
'system.resourcePool.deletePoolSuccess': 'Deleted successfully',
|
'system.resourcePool.deletePoolSuccess': 'Deleted successfully',
|
||||||
'system.resourcePool.detailDesc': 'Description',
|
'system.resourcePool.detailDesc': 'Description',
|
||||||
'system.resourcePool.detailUrl': 'Current site URL',
|
'system.resourcePool.detailUrl': 'Current site URL',
|
||||||
'system.resourcePool.detailRange': 'Available range',
|
'system.resourcePool.detailRange': 'Applied organization',
|
||||||
'system.resourcePool.detailUse': 'Use',
|
'system.resourcePool.detailUse': 'Use',
|
||||||
'system.resourcePool.detailMirror': 'Mirror',
|
'system.resourcePool.detailMirror': 'Mirror',
|
||||||
'system.resourcePool.detailJMHeap': 'JMeter HEAP',
|
'system.resourcePool.detailJMHeap': 'JMeter HEAP',
|
||||||
|
@ -43,7 +43,7 @@ export default {
|
||||||
'system.resourcePool.descPlaceholder': 'Please describe the resource pool',
|
'system.resourcePool.descPlaceholder': 'Please describe the resource pool',
|
||||||
'system.resourcePool.serverUrl': 'Current site URL',
|
'system.resourcePool.serverUrl': 'Current site URL',
|
||||||
'system.resourcePool.rootUrlPlaceholder': 'MS deployment address',
|
'system.resourcePool.rootUrlPlaceholder': 'MS deployment address',
|
||||||
'system.resourcePool.orgRange': 'Application organization',
|
'system.resourcePool.orgRange': 'Applied organization',
|
||||||
'system.resourcePool.orgAll': 'All organization',
|
'system.resourcePool.orgAll': 'All organization',
|
||||||
'system.resourcePool.orgSetup': 'Specified organization',
|
'system.resourcePool.orgSetup': 'Specified organization',
|
||||||
'system.resourcePool.orgSelect': 'specified organization',
|
'system.resourcePool.orgSelect': 'specified organization',
|
||||||
|
@ -122,4 +122,6 @@ export default {
|
||||||
'system.resourcePool.addSuccess': 'Added resource pool successfully',
|
'system.resourcePool.addSuccess': 'Added resource pool successfully',
|
||||||
'system.resourcePool.updateSuccess': 'Resource pool updated successfully',
|
'system.resourcePool.updateSuccess': 'Resource pool updated successfully',
|
||||||
'system.resourcePool.atLeastOnePool': 'Reserve at least one resource pool',
|
'system.resourcePool.atLeastOnePool': 'Reserve at least one resource pool',
|
||||||
|
'system.resourcePool.add': 'Add',
|
||||||
|
'system.resourcePool.addAndContinue': 'Save and continue adding',
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,14 +19,14 @@ export default {
|
||||||
'system.resourcePool.disablePoolCancel': '取消',
|
'system.resourcePool.disablePoolCancel': '取消',
|
||||||
'system.resourcePool.disablePoolSuccess': '禁用成功',
|
'system.resourcePool.disablePoolSuccess': '禁用成功',
|
||||||
'system.resourcePool.deletePoolTip': '确认删除 `{name}` 这个资源吗?',
|
'system.resourcePool.deletePoolTip': '确认删除 `{name}` 这个资源吗?',
|
||||||
'system.resourcePool.deletePoolContentUsed': '该资源池已被使用,删除后相关测试会立即停止,请谨慎操作!',
|
'system.resourcePool.deletePoolContentUsed': '若该资源池已被使用,删除后相关测试会立即停止,请谨慎操作!',
|
||||||
'system.resourcePool.deletePoolContentUnuse': '该资源池未被使用,是否确认删除?',
|
'system.resourcePool.deletePoolContentUnuse': '该资源池未被使用,是否确认删除?',
|
||||||
'system.resourcePool.deletePoolConfirm': '确认删除',
|
'system.resourcePool.deletePoolConfirm': '确认删除',
|
||||||
'system.resourcePool.deletePoolCancel': '取消',
|
'system.resourcePool.deletePoolCancel': '取消',
|
||||||
'system.resourcePool.deletePoolSuccess': '删除成功',
|
'system.resourcePool.deletePoolSuccess': '删除成功',
|
||||||
'system.resourcePool.detailDesc': '描述',
|
'system.resourcePool.detailDesc': '描述',
|
||||||
'system.resourcePool.detailUrl': '当前站点 URL',
|
'system.resourcePool.detailUrl': '当前站点 URL',
|
||||||
'system.resourcePool.detailRange': '可用范围',
|
'system.resourcePool.detailRange': '应用组织',
|
||||||
'system.resourcePool.detailUse': '用途',
|
'system.resourcePool.detailUse': '用途',
|
||||||
'system.resourcePool.detailMirror': '镜像',
|
'system.resourcePool.detailMirror': '镜像',
|
||||||
'system.resourcePool.detailJMHeap': 'JMeter HEAP',
|
'system.resourcePool.detailJMHeap': 'JMeter HEAP',
|
||||||
|
@ -67,7 +67,7 @@ export default {
|
||||||
'system.resourcePool.batchAdd': '批量添加',
|
'system.resourcePool.batchAdd': '批量添加',
|
||||||
'system.resourcePool.batchAddTipConfirm': '知道了',
|
'system.resourcePool.batchAddTipConfirm': '知道了',
|
||||||
'system.resourcePool.batchAddResource': '批量添加资源',
|
'system.resourcePool.batchAddResource': '批量添加资源',
|
||||||
'system.resourcePool.changeAddTypeTip': '切换后,已添加资源内容将继续现在 yaml 内;可批量修改已添加资源',
|
'system.resourcePool.changeAddTypeTip': '切换后,已添加资源内容将继续显示在 yaml 内;可批量修改已添加资源',
|
||||||
'system.resourcePool.changeAddTypePopTitle': '切换添加资源类型?',
|
'system.resourcePool.changeAddTypePopTitle': '切换添加资源类型?',
|
||||||
'system.resourcePool.allUseTip': '如果配置多个测试类型,会存在抢占资源的情况,建议一种测试类型配置一个资源池',
|
'system.resourcePool.allUseTip': '如果配置多个测试类型,会存在抢占资源的情况,建议一种测试类型配置一个资源池',
|
||||||
'system.resourcePool.ip': 'IP',
|
'system.resourcePool.ip': 'IP',
|
||||||
|
@ -117,4 +117,6 @@ export default {
|
||||||
'system.resourcePool.addSuccess': '添加资源池成功',
|
'system.resourcePool.addSuccess': '添加资源池成功',
|
||||||
'system.resourcePool.updateSuccess': '更新资源池成功',
|
'system.resourcePool.updateSuccess': '更新资源池成功',
|
||||||
'system.resourcePool.atLeastOnePool': '至少保留一个资源池',
|
'system.resourcePool.atLeastOnePool': '至少保留一个资源池',
|
||||||
|
'system.resourcePool.add': '添加',
|
||||||
|
'system.resourcePool.addAndContinue': '保存并继续添加',
|
||||||
};
|
};
|
||||||
|
|
|
@ -145,7 +145,7 @@
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<a-button type="secondary" :disabled="loading" @click="cancelCreate">
|
<a-button type="secondary" :disabled="loading" @click="handleBeforeClose">
|
||||||
{{ t('system.user.editUserModalCancelCreate') }}
|
{{ t('system.user.editUserModalCancelCreate') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button v-if="userFormMode === 'create'" type="secondary" :loading="loading" @click="saveAndContinue">
|
<a-button v-if="userFormMode === 'create'" type="secondary" :loading="loading" @click="saveAndContinue">
|
||||||
|
@ -302,7 +302,7 @@
|
||||||
import MsTagGroup from '@/components/pure/ms-tag/ms-tag-group.vue';
|
import MsTagGroup from '@/components/pure/ms-tag/ms-tag-group.vue';
|
||||||
import MsUpload from '@/components/pure/ms-upload/index.vue';
|
import MsUpload from '@/components/pure/ms-upload/index.vue';
|
||||||
import MsBatchForm from '@/components/business/ms-batch-form/index.vue';
|
import MsBatchForm from '@/components/business/ms-batch-form/index.vue';
|
||||||
import type { FormItemModel, MsBatchFormInstance } from '@/components/business/ms-batch-form/types';
|
import type { FormItemModel } from '@/components/business/ms-batch-form/types';
|
||||||
import MsSelect from '@/components/business/ms-select';
|
import MsSelect from '@/components/business/ms-select';
|
||||||
import batchModal from './components/batchModal.vue';
|
import batchModal from './components/batchModal.vue';
|
||||||
import inviteModal from './components/inviteModal.vue';
|
import inviteModal from './components/inviteModal.vue';
|
||||||
|
@ -816,7 +816,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const batchFormRef = ref<MsBatchFormInstance | null>(null);
|
const batchFormRef = ref<InstanceType<typeof MsBatchForm>>();
|
||||||
const batchFormModels: Ref<FormItemModel[]> = ref([
|
const batchFormModels: Ref<FormItemModel[]> = ref([
|
||||||
{
|
{
|
||||||
filed: 'name',
|
filed: 'name',
|
||||||
|
@ -933,7 +933,7 @@
|
||||||
} else {
|
} else {
|
||||||
Message.success(t('system.user.addUserSuccess'));
|
Message.success(t('system.user.addUserSuccess'));
|
||||||
if (!isContinue) {
|
if (!isContinue) {
|
||||||
visible.value = false;
|
cancelCreate();
|
||||||
}
|
}
|
||||||
loadList();
|
loadList();
|
||||||
}
|
}
|
||||||
|
@ -981,6 +981,7 @@
|
||||||
userFormValidate(async () => {
|
userFormValidate(async () => {
|
||||||
await createUser(true);
|
await createUser(true);
|
||||||
resetUserForm();
|
resetUserForm();
|
||||||
|
batchFormRef.value?.resetForm();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const currentKeyword = ref('');
|
const currentKeyword = ref('');
|
||||||
const ugLeftRef = ref();
|
const ugLeftRef = ref<InstanceType<typeof UserGroupLeft>>();
|
||||||
|
|
||||||
const currentUserGroupItem = ref<CurrentUserGroupItem>({
|
const currentUserGroupItem = ref<CurrentUserGroupItem>({
|
||||||
id: '',
|
id: '',
|
||||||
|
@ -147,7 +147,7 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
ugLeftRef.value?.initData(router.currentRoute.value.query.id, true);
|
ugLeftRef.value?.initData(router.currentRoute.value.query.id as string, true);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue