feat: 资源池接口联调&部分组件调整

This commit is contained in:
baiqi 2023-07-24 17:46:32 +08:00 committed by fit2-zhao
parent 54640dc32d
commit 4ebc36d5a9
14 changed files with 297 additions and 109 deletions

View File

@ -1,8 +1,20 @@
import MSR from '@/api/http/index'; import MSR from '@/api/http/index';
import { PoolListUrl, UpdatePoolUrl, AddPoolUrl, DetailPoolUrl } from '@/api/requrls/setting/resourcePool'; import {
PoolListUrl,
UpdatePoolUrl,
AddPoolUrl,
DetailPoolUrl,
DeletePoolUrl,
EnablePoolUrl,
} from '@/api/requrls/setting/resourcePool';
import type { LocationQueryValue } from 'vue-router'; import type { LocationQueryValue } from 'vue-router';
import type { ResourcePoolItem, AddResourcePoolParams } from '@/models/setting/resourcePool'; import type {
ResourcePoolItem,
AddResourcePoolParams,
UpdateResourcePoolParams,
ResourcePoolDetail,
} from '@/models/setting/resourcePool';
import type { TableQueryParams } from '@/models/common'; import type { TableQueryParams } from '@/models/common';
// 获取资源池列表 // 获取资源池列表
@ -11,7 +23,7 @@ export function getPoolList(data: TableQueryParams) {
} }
// 更新资源池信息 // 更新资源池信息
export function updatePoolInfo(data: ResourcePoolItem) { export function updatePoolInfo(data: UpdateResourcePoolParams) {
return MSR.post({ url: UpdatePoolUrl, data }); return MSR.post({ url: UpdatePoolUrl, data });
} }
@ -22,5 +34,15 @@ export function addPool(data: AddResourcePoolParams) {
// 获取资源池详情 // 获取资源池详情
export function getPoolInfo(poolId: LocationQueryValue | LocationQueryValue[]) { export function getPoolInfo(poolId: LocationQueryValue | LocationQueryValue[]) {
return MSR.get<ResourcePoolItem>({ url: DetailPoolUrl, params: poolId }); return MSR.get<ResourcePoolDetail>({ url: DetailPoolUrl, params: poolId });
}
// 删除资源池
export function delPoolInfo(poolId: string) {
return MSR.get({ url: DeletePoolUrl, params: poolId });
}
// 启用/禁用资源池
export function togglePoolStatus(poolId: string) {
return MSR.post({ url: EnablePoolUrl, params: poolId });
} }

View File

@ -3,3 +3,4 @@ export const UpdatePoolUrl = '/test/resource/pool/update';
export const AddPoolUrl = '/test/resource/pool/add'; export const AddPoolUrl = '/test/resource/pool/add';
export const DeletePoolUrl = '/test/resource/pool/delete'; export const DeletePoolUrl = '/test/resource/pool/delete';
export const DetailPoolUrl = '/test/resource/pool/detail'; export const DetailPoolUrl = '/test/resource/pool/detail';
export const EnablePoolUrl = '/test/resource/pool/set/enable/';

View File

@ -7,7 +7,13 @@
</div> </div>
<a-divider v-if="!simple" class="mb-[16px]" /> <a-divider v-if="!simple" class="mb-[16px]" />
<div class="mr-[-10px]"> <div class="mr-[-10px]">
<a-scrollbar class="pr-[10px]" style="overflow-y: auto; height: calc(100vh - 256px)"> <a-scrollbar
class="pr-[10px]"
:style="{
overflowY: 'auto',
height: `calc(100vh - ${256 + specialHeight}px)`,
}"
>
<slot></slot> <slot></slot>
</a-scrollbar> </a-scrollbar>
</div> </div>
@ -20,11 +26,11 @@
</div> </div>
<slot name="footerRight"> <slot name="footerRight">
<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" type="secondary" @click="emit('saveAndContinue')"> <a-button v-if="!props.hideContinue && !props.isEdit" type="secondary" @click="emit('saveAndContinue')">
{{ t('mscard.defaultSaveAndContinueText') }} {{ t('mscard.defaultSaveAndContinueText') }}
</a-button> </a-button>
<a-button type="primary" @click="emit('save')"> <a-button type="primary" @click="emit('save')">
{{ t(idEdit ? 'mscard.defaultConfirm' : 'mscard.defaultUpdate') }} {{ t(props.isEdit ? 'mscard.defaultUpdate' : 'mscard.defaultConfirm') }}
</a-button> </a-button>
</slot> </slot>
</div> </div>
@ -37,20 +43,24 @@
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<
simple?: boolean; Partial<{
title?: string; simple: boolean;
hideContinue?: boolean; title: string;
handleBack?: () => void; hideContinue: boolean;
hideFooter?: boolean; hideFooter: boolean;
loading?: boolean; loading: boolean;
idEdit?: boolean; isEdit: boolean;
}>(), specialHeight: number; //
handleBack: () => void;
}>
>(),
{ {
simple: false, simple: false,
hideContinue: false, hideContinue: false,
hideFooter: false, hideFooter: false,
idEdit: false, isEdit: false,
specialHeight: 0,
} }
); );

View File

@ -58,6 +58,10 @@ export const editorProps = {
}, },
default: 'vs-dark', default: 'vs-dark',
}, },
readOnly: {
type: Boolean as PropType<boolean>,
default: false,
},
options: { options: {
type: Object as PropType<Options>, type: Object as PropType<Options>,
default() { default() {

View File

@ -1,5 +1,5 @@
import * as monaco from 'monaco-editor'; import * as monaco from 'monaco-editor';
import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'; // import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
// import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'; // import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
// import CssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'; // import CssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker';
// import HtmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'; // import HtmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker';
@ -26,6 +26,7 @@ self.MonacoEnvironment = {
return new TsWorker(); return new TsWorker();
} }
const EditorWorker = ((await import('monaco-editor/esm/vs/editor/editor.worker?worker')) as any).default;
return new EditorWorker(); return new EditorWorker();
}, },
}; };

View File

@ -13,8 +13,17 @@
<div v-else class="ms-upload-icon ms-upload-icon--default"></div> <div v-else class="ms-upload-icon ms-upload-icon--default"></div>
</div> </div>
<template v-if="fileList.length === 0"> <template v-if="fileList.length === 0">
<div v-if="props.mainText" class="ms-upload-main-text">{{ t(props.mainText) }}</div> <div class="ms-upload-main-text">
<div v-if="props.subText" class="ms-upload-sub-text">{{ t(props.subText) }}</div> {{ t(props.mainText || 'ms.upload.importModalDragtext') }}
</div>
<div class="ms-upload-sub-text">
{{
t(props.subText || 'ms.upload.importModalFileTip', {
type: UploadAcceptEnum[props.accept],
size: props.maxSize || defaultMaxSize,
})
}}
</div>
</template> </template>
<template v-else> <template v-else>
<div class="ms-upload-main-text"> <div class="ms-upload-main-text">
@ -31,23 +40,24 @@
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import { UploadAcceptEnum } from '@/enums/uploadEnum'; import { UploadAcceptEnum } from '@/enums/uploadEnum';
import { formatFileSize, sleep } from '@/utils'; import { formatFileSize } from '@/utils';
import MsIcon from '@/components/pure/ms-icon-font/index.vue'; import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import type { FileItem } from '@arco-design/web-vue'; import { FileItem, Message } from '@arco-design/web-vue';
import type { UploadType } from './types'; import type { UploadType } from './types';
const { t } = useI18n(); const { t } = useI18n();
// props // props
type UploadProps = Partial<{ type UploadProps = Partial<{
mainText: string; mainText: string; //
subText: string; subText: string; //
class: string; class: string;
multiple: boolean; multiple: boolean;
imagePreview: boolean; imagePreview: boolean;
showFileList: boolean; showFileList: boolean;
iconType: string; iconType: string;
maxSize: number; // MB
[key: string]: any; [key: string]: any;
}> & { }> & {
accept: UploadType; accept: UploadType;
@ -57,6 +67,8 @@
const props = defineProps<UploadProps>(); const props = defineProps<UploadProps>();
const emit = defineEmits(['update:fileList']); const emit = defineEmits(['update:fileList']);
const defaultMaxSize = 50;
const fileList = ref<FileItem[]>(props.fileList); const fileList = ref<FileItem[]>(props.fileList);
watch( watch(
@ -80,11 +92,16 @@
jar: 'icon-icon_file-jar_colorful', jar: 'icon-icon_file-jar_colorful',
}; };
async function beforeUpload() { async function beforeUpload(file: File) {
if (!props.multiple && fileList.value.length > 0) { if (!props.multiple && fileList.value.length > 0) {
// //
fileList.value = []; fileList.value = [];
} }
const maxSize = props.maxSize || defaultMaxSize;
if (file.size > maxSize * 1024 * 1024) {
Message.warning(t('ms.upload.overSize'));
return Promise.resolve(false);
}
return Promise.resolve(true); return Promise.resolve(true);
} }
</script> </script>

View File

@ -1,3 +1,6 @@
export default { export default {
'ms.upload.changeFile': 'Change file', 'ms.upload.changeFile': 'Change file',
'ms.upload.overSize': 'The file size exceeds the limit, please reselect the file',
'ms.upload.importModalDragtext': 'Drag or click this area to select a file',
'ms.upload.importModalFileTip': 'Only {type} format files are supported, and the file size does not exceed {size} MB',
}; };

View File

@ -1,3 +1,6 @@
export default { export default {
'ms.upload.changeFile': '更改文件', 'ms.upload.changeFile': '更改文件',
'ms.upload.overSize': '文件大小超出限制,请重新选择文件',
'ms.upload.importModalDragtext': '拖拽或点击此区域选择文件',
'ms.upload.importModalFileTip': '只支持 {type} 格式文件,文件大小不超过 {size} MB',
}; };

View File

@ -9,4 +9,6 @@ export enum TableModuleEnum {
export enum TableKeyEnum { export enum TableKeyEnum {
API_TEST = 'apiTest', API_TEST = 'apiTest',
USERGROUPUSER = 'userGroupUser', USERGROUPUSER = 'userGroupUser',
SYSTEM_USER = 'systemUser',
SYSTEM_RESOURCEPOOL = 'systemResourcePool',
} }

View File

@ -39,7 +39,7 @@
:style="{ :style="{
overflow: 'auto', overflow: 'auto',
width: `calc(100vw - ${menuWidth}px)`, width: `calc(100vw - ${menuWidth}px)`,
height: 'calc(100vh - 72px)', height: 'calc(100vh - 64px)',
}" }"
> >
<MsBreadCrumb /> <MsBreadCrumb />

View File

@ -6,6 +6,12 @@ export interface NodesListItem {
concurrentNumber: number; concurrentNumber: number;
} }
// 应用组织id和name映射对象
export interface OrgIdNameMap {
id: string;
name: string;
}
// 资源池配置信息对象 // 资源池配置信息对象
export interface TestResourceDTO { export interface TestResourceDTO {
loadTestImage: string; // 镜像 loadTestImage: string; // 镜像
@ -22,6 +28,7 @@ export interface TestResourceDTO {
uiGrid: string; // ui测试selenium-grid uiGrid: string; // ui测试selenium-grid
girdConcurrentNumber: number; // ui测试selenium-grid最大并发数 girdConcurrentNumber: number; // ui测试selenium-grid最大并发数
orgIds: string[]; // 应用范围选择指定组织时的id集合 orgIds: string[]; // 应用范围选择指定组织时的id集合
orgIdNameMap: OrgIdNameMap[]; // 应用范围选择指定组织时的id和name映射
} }
// 资源池信息对象 // 资源池信息对象
@ -43,7 +50,18 @@ export interface ResourcePoolItem extends ResourcePoolInfo {
id: string; id: string;
} }
export type ResourcePoolDetail = Omit<ResourcePoolInfo, 'testResourceDTO'> & {
id: string;
testResourceReturnDTO: TestResourceDTO;
};
// 添加资源池参数对象 // 添加资源池参数对象
export type AddResourcePoolParams = Omit<ResourcePoolInfo, 'testResourceDTO'> & { export type AddResourcePoolParams = Omit<ResourcePoolInfo, 'testResourceDTO'> & {
testResourceDTO?: Partial<TestResourceDTO>; testResourceDTO?: Partial<TestResourceDTO>;
}; };
// 更新资源池参数对象
export type UpdateResourcePoolParams = Omit<ResourcePoolInfo, 'testResourceDTO'> & {
id: string;
testResourceDTO?: Partial<TestResourceDTO>;
};

View File

@ -1,11 +1,18 @@
<template> <template>
<MsDrawer v-model:visible="showJobDrawer" width="680px" :title="t('system.resourcePool.customJobTemplate')"> <MsDrawer
v-model:visible="showJobDrawer"
width="680px"
:title="t('system.resourcePool.customJobTemplate')"
:footer="false"
@close="handleClose"
>
<MsCodeEditor <MsCodeEditor
v-model:model-value="jobDefinition" v-model:model-value="jobDefinition"
title="YAML" title="YAML"
width="100%" width="100%"
height="calc(100vh - 205px)" height="calc(100vh - 205px)"
theme="MS-text" theme="MS-text"
:read-only="props.readOnly"
/> />
</MsDrawer> </MsDrawer>
</template> </template>
@ -18,14 +25,16 @@
const props = defineProps<{ const props = defineProps<{
visible: boolean; visible: boolean;
value: string | null; value?: string | null;
defaultVal?: string | null;
readOnly?: boolean;
}>(); }>();
const emit = defineEmits(['update:value', 'update:visible']); const emit = defineEmits(['update:value', 'update:visible']);
const { t } = useI18n(); const { t } = useI18n();
const showJobDrawer = ref(props.visible); const showJobDrawer = ref(props.visible);
const jobDefinition = ref(props.value || ''); const jobDefinition = ref(props.defaultVal || props.value || '');
watch( watch(
() => props.visible, () => props.visible,
@ -34,12 +43,34 @@
} }
); );
watch(
() => props.defaultVal,
(val) => {
if (val) {
jobDefinition.value = val;
}
}
);
watch(
() => props.value,
(val) => {
if (val) {
jobDefinition.value = val;
}
}
);
watch( watch(
() => showJobDrawer.value, () => showJobDrawer.value,
(val) => { (val) => {
emit('update:visible', val); emit('update:visible', val);
} }
); );
function handleClose() {
emit('update:value', jobDefinition.value);
}
</script> </script>
<style lang="less" scoped></style> <style lang="less" scoped></style>

View File

@ -1,5 +1,12 @@
<template> <template>
<MsCard :loading="loading" :title="title" @save="beforeSave" @save-and-continue="beforeSave(true)"> <MsCard
:loading="loading"
:title="title"
:is-edit="isEdit"
:special-height="34"
@save="beforeSave"
@save-and-continue="beforeSave(true)"
>
<a-form ref="formRef" :model="form" layout="vertical"> <a-form ref="formRef" :model="form" layout="vertical">
<a-form-item <a-form-item
:label="t('system.resourcePool.name')" :label="t('system.resourcePool.name')"
@ -318,15 +325,15 @@
</template> </template>
</a-form> </a-form>
<template #footerLeft> <template #footerLeft>
<a-button v-if="isCheckedPerformance" type="text" @click="showJobDrawer = true"> <MsButton v-if="isCheckedPerformance && isShowK8SResources" @click="showJobDrawer = true">
{{ t('system.resourcePool.customJobTemplate') }} {{ t('system.resourcePool.customJobTemplate') }}
<a-tooltip :content="t('system.resourcePool.jobTemplateTip')" position="tl" mini> <a-tooltip :content="t('system.resourcePool.jobTemplateTip')" position="tl" mini>
<icon-question-circle class="ml-[4px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-6))]" /> <icon-question-circle class="ml-[4px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-6))]" />
</a-tooltip> </a-tooltip>
</a-button> </MsButton>
</template> </template>
</MsCard> </MsCard>
<JobTemplateDrawer v-model:visible="showJobDrawer" :value="form.testResourceDTO.jobDefinition" /> <JobTemplateDrawer v-model:visible="showJobDrawer" v-model:value="form.testResourceDTO.jobDefinition" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -336,16 +343,17 @@
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useVisit from '@/hooks/useVisit'; import useVisit from '@/hooks/useVisit';
import MsCard from '@/components/pure/ms-card/index.vue'; import MsCard from '@/components/pure/ms-card/index.vue';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsBatchForm from '@/components/bussiness/ms-batch-form/index.vue'; import MsBatchForm from '@/components/bussiness/ms-batch-form/index.vue';
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue'; import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
import JobTemplateDrawer from './components/jobTemplateDrawer.vue'; import JobTemplateDrawer from './components/jobTemplateDrawer.vue';
import { getYaml, YamlType, job } from './template'; import { getYaml, YamlType, job } from './template';
import { downloadStringFile, sleep } from '@/utils'; import { downloadStringFile, sleep } from '@/utils';
import { scrollIntoView } from '@/utils/dom'; import { scrollIntoView } from '@/utils/dom';
import { addPool, getPoolInfo } from '@/api/modules/setting/resourcePool'; import { addPool, getPoolInfo, updatePoolInfo } from '@/api/modules/setting/resourcePool';
import type { MsBatchFormInstance, FormItemModel } from '@/components/bussiness/ms-batch-form/types'; import type { MsBatchFormInstance, FormItemModel } from '@/components/bussiness/ms-batch-form/types';
import type { AddResourcePoolParams, NodesListItem } from '@/models/setting/resourcePool'; import type { UpdateResourcePoolParams, NodesListItem } from '@/models/setting/resourcePool';
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
@ -402,18 +410,19 @@
try { try {
loading.value = true; loading.value = true;
const res = await getPoolInfo(route.query.id); const res = await getPoolInfo(route.query.id);
const { testResourceDTO } = res; const { testResourceReturnDTO } = res;
const { girdConcurrentNumber, podThreads, concurrentNumber } = testResourceDTO; const { girdConcurrentNumber, podThreads, concurrentNumber, orgIdNameMap } = testResourceReturnDTO;
form.value = { form.value = {
...res, ...res,
addType: 'single', addType: 'single',
orgType: res.allOrg ? 'allOrg' : 'set', orgType: res.allOrg ? 'allOrg' : 'set',
use: [res.loadTest ? 'performance' : '', res.apiTest ? 'API' : '', res.uiTest ? 'UI' : ''].filter((e) => e), use: [res.loadTest ? 'performance' : '', res.apiTest ? 'API' : '', res.uiTest ? 'UI' : ''].filter((e) => e),
testResourceDTO: { testResourceDTO: {
...testResourceDTO, ...testResourceReturnDTO,
girdConcurrentNumber: girdConcurrentNumber || 1, girdConcurrentNumber: girdConcurrentNumber || 1,
podThreads: podThreads || 1, podThreads: podThreads || 1,
concurrentNumber: concurrentNumber || 1, concurrentNumber: concurrentNumber || 1,
orgIds: orgIdNameMap?.map((e) => e.id) || [],
}, },
}; };
} catch (error) { } catch (error) {
@ -558,10 +567,9 @@
* 解析代码编辑器内容 * 解析代码编辑器内容
*/ */
function analyzeCode() { function analyzeCode() {
const arr = editorContent.value.split('\r'); // const arr = editorContent.value.replaceAll('\r', '\n').split('\n'); //
// //
arr.forEach((e, i) => { arr.forEach((e, i) => {
e = e.replaceAll('\n', ''); //
if (e.trim() !== '') { if (e.trim() !== '') {
// //
const line = e.split(','); const line = e.split(',');
@ -648,7 +656,7 @@
/** /**
* 拼接添加资源池参数 * 拼接添加资源池参数
*/ */
function makeResourcePoolParams(): AddResourcePoolParams { function makeResourcePoolParams(): UpdateResourcePoolParams {
const { type, testResourceDTO } = form.value; const { type, testResourceDTO } = form.value;
const { const {
ip, ip,
@ -678,7 +686,6 @@
nameSpaces, nameSpaces,
concurrentNumber, concurrentNumber,
podThreads, podThreads,
jobDefinition,
apiTestImage, apiTestImage,
deployName, deployName,
} }
@ -706,14 +713,16 @@
girdConcurrentNumber, girdConcurrentNumber,
} }
: {}; : {};
const jobDTO = isCheckedPerformance.value && isShowK8SResources ? { jobDefinition } : {};
return { return {
...form.value, ...form.value,
type: isShowTypeItem.value ? form.value.type : '', type: isShowTypeItem.value ? form.value.type : 'Node', // Node
allOrg: form.value.orgType === 'allOrg', allOrg: form.value.orgType === 'allOrg',
apiTest: form.value.use.includes('API'), // api apiTest: form.value.use.includes('API'), // api
loadTest: form.value.use.includes('performance'), // loadTest: form.value.use.includes('performance'), //
uiTest: form.value.use.includes('UI'), // ui uiTest: form.value.use.includes('UI'), // ui
testResourceDTO: { ...performanceDTO, ...apiDTO, ...uiDTO, orgIds: form.value.testResourceDTO.orgIds }, testResourceDTO: { ...performanceDTO, ...apiDTO, ...uiDTO, ...jobDTO, orgIds: form.value.testResourceDTO.orgIds },
}; };
} }
@ -721,8 +730,13 @@
try { try {
loading.value = true; loading.value = true;
const params = makeResourcePoolParams(); const params = makeResourcePoolParams();
if (isEdit.value) {
await updatePoolInfo(params);
Message.success(t('system.resourcePool.updateSuccess'));
} else {
await addPool(params); await addPool(params);
Message.success(t('system.resourcePool.addSuccess')); Message.success(t('system.resourcePool.addSuccess'));
}
if (isContinueAdd.value) { if (isContinueAdd.value) {
resetForm(); resetForm();
} else { } else {
@ -795,4 +809,3 @@
} }
} }
</style> </style>
@/models/setting/resourcePool @/api/modules/setting/resourcePool

View File

@ -1,12 +1,17 @@
<template> <template>
<div>
<MsCard :loading="loading" simple>
<div class="mb-4 flex items-center justify-between"> <div class="mb-4 flex items-center justify-between">
<a-button type="primary" @click="addPool"> <a-button type="primary" @click="addPool">
{{ t('system.resourcePool.createPool') }} {{ t('system.resourcePool.createPool') }}
</a-button> </a-button>
<a-input-search <a-input-search
v-model:model-value="keyword"
:placeholder="t('system.resourcePool.searchPool')" :placeholder="t('system.resourcePool.searchPool')"
class="w-[230px]" class="w-[230px]"
allow-clear
@search="searchPool" @search="searchPool"
@press-enter="searchPool"
></a-input-search> ></a-input-search>
</div> </div>
<ms-base-table v-bind="propsRes" no-disable v-on="propsEvent"> <ms-base-table v-bind="propsRes" no-disable v-on="propsEvent">
@ -32,6 +37,7 @@
<MsTableMoreAction :list="tableActions" @select="handleSelect($event, record)"></MsTableMoreAction> <MsTableMoreAction :list="tableActions" @select="handleSelect($event, record)"></MsTableMoreAction>
</template> </template>
</ms-base-table> </ms-base-table>
</MsCard>
<MsDrawer <MsDrawer
v-model:visible="showDetailDrawer" v-model:visible="showDetailDrawer"
width="480px" width="480px"
@ -48,7 +54,12 @@
</a-button> </a-button>
</template> </template>
</MsDrawer> </MsDrawer>
<JobTemplateDrawer v-model:visible="showJobDrawer" :value="activePool?.testResourceDTO.jobDefinition || ''" /> <JobTemplateDrawer
v-model:visible="showJobDrawer"
:default-val="activePool?.testResourceDTO.jobDefinition || ''"
read-only
/>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -56,14 +67,17 @@
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { Message } from '@arco-design/web-vue'; import { Message } from '@arco-design/web-vue';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import { getPoolList } from '@/api/modules/setting/resourcePool'; import { getPoolList, delPoolInfo, togglePoolStatus } from '@/api/modules/setting/resourcePool';
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
import MsCard from '@/components/pure/ms-card/index.vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue'; import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import useTable from '@/components/pure/ms-table/useTable'; import useTable from '@/components/pure/ms-table/useTable';
import MsButton from '@/components/pure/ms-button/index.vue'; import MsButton from '@/components/pure/ms-button/index.vue';
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue'; import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
import MsDrawer from '@/components/pure/ms-drawer/index.vue'; import MsDrawer from '@/components/pure/ms-drawer/index.vue';
import JobTemplateDrawer from './components/jobTemplateDrawer.vue'; import JobTemplateDrawer from './components/jobTemplateDrawer.vue';
import { TableKeyEnum } from '@/enums/tableEnum';
import { useTableStore } from '@/store';
import type { Description } from '@/components/pure/ms-description/index.vue'; import type { Description } from '@/components/pure/ms-description/index.vue';
import type { MsTableColumn } from '@/components/pure/ms-table/type'; import type { MsTableColumn } from '@/components/pure/ms-table/type';
@ -79,37 +93,46 @@
slotName: 'name', slotName: 'name',
dataIndex: 'name', dataIndex: 'name',
width: 200, width: 200,
showInTable: true,
}, },
{ {
title: 'system.resourcePool.tableColunmStatus', title: 'system.resourcePool.tableColunmStatus',
slotName: 'enable', slotName: 'enable',
dataIndex: 'enable', dataIndex: 'enable',
showInTable: true,
}, },
{ {
title: 'system.resourcePool.tableColunmDescription', title: 'system.resourcePool.tableColunmDescription',
dataIndex: 'description', dataIndex: 'description',
showInTable: true,
}, },
{ {
title: 'system.resourcePool.tableColunmType', title: 'system.resourcePool.tableColunmType',
dataIndex: 'type', dataIndex: 'type',
showInTable: true,
}, },
{ {
title: 'system.resourcePool.tableColunmCreateTime', title: 'system.resourcePool.tableColunmCreateTime',
dataIndex: 'createTime', dataIndex: 'createTime',
showInTable: true,
}, },
{ {
title: 'system.resourcePool.tableColunmUpdateTime', title: 'system.resourcePool.tableColunmUpdateTime',
dataIndex: 'updateTime', dataIndex: 'updateTime',
showInTable: true,
}, },
{ {
title: 'system.resourcePool.tableColunmActions', title: 'system.resourcePool.tableColunmActions',
slotName: 'action', slotName: 'action',
fixed: 'right', fixed: 'right',
width: 120, width: 120,
showInTable: true,
}, },
]; ];
const tableStore = useTableStore();
tableStore.initColumn(TableKeyEnum.SYSTEM_RESOURCEPOOL, columns, 'drawer');
const { propsRes, propsEvent, loadList, setKeyword } = useTable(getPoolList, { const { propsRes, propsEvent, loadList, setKeyword } = useTable(getPoolList, {
tableKey: TableKeyEnum.SYSTEM_RESOURCEPOOL,
columns, columns,
scroll: { y: 'auto' }, scroll: { y: 'auto' },
selectable: false, selectable: false,
@ -138,19 +161,25 @@
}, },
]; ];
const loading = ref(false);
/** /**
* 启用资源池 * 启用资源池
*/ */
function enablePool(record: any) { async function enablePool(record: any) {
try { try {
loading.value = true;
await togglePoolStatus(record.id);
Message.success(t('system.resourcePool.enablePoolSuccess')); Message.success(t('system.resourcePool.enablePoolSuccess'));
return true; loadList();
} catch (error) { } catch (error) {
console.log(error); console.log(error);
return false; } finally {
loading.value = false;
} }
} }
const disableLoading = ref(false);
/** /**
* 禁用资源池 * 禁用资源池
*/ */
@ -164,19 +193,30 @@
okButtonProps: { okButtonProps: {
status: 'danger', status: 'danger',
}, },
cancelButtonProps: {
disabled: disableLoading.value,
},
okLoading: disableLoading.value,
maskClosable: false,
onBeforeOk: async () => { onBeforeOk: async () => {
try { try {
disableLoading.value = true;
await togglePoolStatus(record.id);
Message.success(t('system.resourcePool.disablePoolSuccess')); Message.success(t('system.resourcePool.disablePoolSuccess'));
loadList();
return true; return true;
} catch (error) { } catch (error) {
console.log(error); console.log(error);
return false; return false;
} finally {
disableLoading.value = false;
} }
}, },
hideCancel: false, hideCancel: false,
}); });
} }
const delLoading = ref(false);
/** /**
* 删除资源池 * 删除资源池
*/ */
@ -190,13 +230,23 @@
okButtonProps: { okButtonProps: {
status: 'danger', status: 'danger',
}, },
cancelButtonProps: {
disabled: delLoading.value,
},
maskClosable: false,
okLoading: delLoading.value,
onBeforeOk: async () => { onBeforeOk: async () => {
try { try {
delLoading.value = true;
await delPoolInfo(record.id);
Message.success(t('system.resourcePool.deletePoolSuccess')); Message.success(t('system.resourcePool.deletePoolSuccess'));
loadList();
return true; return true;
} catch (error) { } catch (error) {
console.log(error); console.log(error);
return false; return false;
} finally {
delLoading.value = false;
} }
}, },
hideCancel: false, hideCancel: false,
@ -242,6 +292,7 @@
podThreads, // k8s pod线 podThreads, // k8s pod线
apiTestImage, // k8s api apiTestImage, // k8s api
deployName, // k8s api deployName, // k8s api
girdConcurrentNumber,
nodesList, nodesList,
loadTestImage, loadTestImage,
loadTestHeap, loadTestHeap,
@ -290,6 +341,11 @@
label: t('system.resourcePool.testResourceDTO.podThreads'), label: t('system.resourcePool.testResourceDTO.podThreads'),
value: podThreads, value: podThreads,
}, },
]
: [];
const jobTemplate =
loadTest && type === 'Kubernetes'
? [
{ {
label: t('system.resourcePool.jobTemplate'), label: t('system.resourcePool.jobTemplate'),
value: t('system.resourcePool.customJobTemplate'), value: t('system.resourcePool.customJobTemplate'),
@ -324,7 +380,17 @@
}, },
{ {
label: t('system.resourcePool.concurrentNumber'), label: t('system.resourcePool.concurrentNumber'),
value: concurrentNumber, value: girdConcurrentNumber,
},
]
: [];
const detailType =
apiTest || loadTest
? [
{
label: t('system.resourcePool.detailType'),
value: activePool.value.type,
}, },
] ]
: []; : [];
@ -341,7 +407,7 @@
label: t('system.resourcePool.detailRange'), label: t('system.resourcePool.detailRange'),
value: activePool.value.allOrg value: activePool.value.allOrg
? [t('system.resourcePool.orgAll')] ? [t('system.resourcePool.orgAll')]
: activePool.value.testResourceDTO.orgIds.join(','), : activePool.value.testResourceDTO.orgIdNameMap.map((e) => e.name),
isTag: true, isTag: true,
}, },
{ {
@ -351,11 +417,9 @@
}, },
...performanceDesc, ...performanceDesc,
...uiDesc, ...uiDesc,
{ ...detailType,
label: t('system.resourcePool.detailType'),
value: activePool.value.type,
},
...resourceDesc, ...resourceDesc,
...jobTemplate,
]; ];
} }
@ -379,7 +443,7 @@
* 添加资源池 * 添加资源池
* @param record * @param record
*/ */
function addPool(record: any) { function addPool() {
router.push({ router.push({
name: 'settingSystemResourcePoolDetail', name: 'settingSystemResourcePoolDetail',
}); });
@ -387,4 +451,3 @@
</script> </script>
<style lang="less" scoped></style> <style lang="less" scoped></style>
@/models/setting/resourcePool @/api/modules/setting/resourcePool