refactor(项目管理): 环境变量接口对接

This commit is contained in:
RubyLiu 2024-02-29 19:39:34 +08:00 committed by Craftsman
parent e28284be97
commit 213de72e3b
16 changed files with 357 additions and 172 deletions

View File

@ -3,11 +3,9 @@ import { FileItem } from '@arco-design/web-vue';
import MSR from '@/api/http/index'; import MSR from '@/api/http/index';
import * as envURL from '@/api/requrls/project-management/envManagement'; import * as envURL from '@/api/requrls/project-management/envManagement';
import { DragCase } from '@/models/caseManagement/featureCase';
import type { import type {
DragParam, DragParam,
EnvDetailItem, EnvDetailItem,
EnvGroupListItem,
EnvListItem, EnvListItem,
EnvPluginListItem, EnvPluginListItem,
GlobalParams, GlobalParams,
@ -27,14 +25,17 @@ export function updateOrAddEnv(data: { request: EnvDetailItem; fileList: FileIte
export function listEnv(data: { projectId: string; keyword: string }) { export function listEnv(data: { projectId: string; keyword: string }) {
return MSR.post<EnvListItem[]>({ url: envURL.listEnvUrl, data }); return MSR.post<EnvListItem[]>({ url: envURL.listEnvUrl, data });
} }
export function importEnv(data: { request: EnvListItem; fileList: FileItem[] }) { export function importEnv(data: { request: any; fileList: FileItem[] }) {
return MSR.uploadFile({ url: envURL.importEnvUrl }, data, '', true); return MSR.uploadFile({ url: envURL.importEnvUrl }, data, '', false);
} }
export function getEntryEnv(data: EnvListItem) { export function getEntryEnv(data: EnvListItem) {
return MSR.post<EnvListItem>({ url: envURL.getEntryEnvUrl, data }); return MSR.post<EnvListItem>({ url: envURL.getEntryEnvUrl, data });
} }
export function exportEnv(id: string) { export function exportEnv(selectIds: string[]) {
return MSR.get<EnvListItem>({ url: envURL.exportEnvUrl + id, responseType: 'blob' }, { isTransformResponse: false }); return MSR.post<Blob>(
{ url: envURL.exportEnvUrl, data: { selectIds }, responseType: 'blob' },
{ isTransformResponse: false }
);
} }
export function editPosEnv(data: EnvListItem) { export function editPosEnv(data: EnvListItem) {
return MSR.post<EnvListItem>({ url: envURL.editPosEnvUrl, data }); return MSR.post<EnvListItem>({ url: envURL.editPosEnvUrl, data });
@ -55,8 +56,8 @@ export function addEnv(data: EnvListItem) {
export function getDetailEnv(id: string) { export function getDetailEnv(id: string) {
return MSR.get<EnvDetailItem>({ url: envURL.detailEnvUrl + id }); return MSR.get<EnvDetailItem>({ url: envURL.detailEnvUrl + id });
} }
export function deleteEnv(data: EnvListItem) { export function deleteEnv(id: string) {
return MSR.post<EnvListItem>({ url: envURL.deleteEnvUrl, data }); return MSR.get<EnvListItem>({ url: envURL.deleteEnvUrl + id });
} }
export function groupUpdateEnv(data: any) { export function groupUpdateEnv(data: any) {
return MSR.post<EnvListItem>({ url: envURL.groupUpdateEnvUrl, data }); return MSR.post<EnvListItem>({ url: envURL.groupUpdateEnvUrl, data });

View File

@ -125,6 +125,8 @@
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import { EnvListItem } from '@/models/projectManagement/environmental';
import { MsExportDrawerMap, MsExportDrawerOption } from './types'; import { MsExportDrawerMap, MsExportDrawerOption } from './types';
const { t } = useI18n(); const { t } = useI18n();
@ -136,6 +138,8 @@
allData: MsExportDrawerMap; allData: MsExportDrawerMap;
// keys // keys
defaultSelectedKeys?: string[]; defaultSelectedKeys?: string[];
isArrayColumn?: boolean;
arrayColumn?: EnvListItem[];
} }
const props = withDefaults(defineProps<MsExportDrawerProps>(), { const props = withDefaults(defineProps<MsExportDrawerProps>(), {
@ -161,6 +165,15 @@
}); });
const systemList = computed(() => { const systemList = computed(() => {
if (props.isArrayColumn && props.arrayColumn) {
return props.arrayColumn.map((item) => {
return {
key: item.id,
text: item.name,
columnType: 'system',
};
});
}
const { systemColumns } = props.allData; const { systemColumns } = props.allData;
if (systemColumns) { if (systemColumns) {
return Object.keys(systemColumns).map((key) => { return Object.keys(systemColumns).map((key) => {

View File

@ -10,4 +10,5 @@ export interface MsExportDrawerOption {
text: string; text: string;
key: string; key: string;
columnType: string; columnType: string;
[key: string]: any;
} }

View File

@ -1,3 +1,5 @@
import { ExecuteConditionProcessor } from '../apiTest/debug';
export interface EnvListItem { export interface EnvListItem {
name: string; name: string;
id: string; id: string;
@ -29,17 +31,19 @@ export interface DataSourceItem {
export interface EnvConfigItem { export interface EnvConfigItem {
[key: string]: any; [key: string]: any;
} }
export interface ProcessorConfig {
apiProcessorConfig: ExecuteConditionProcessor[];
}
export interface EnvConfig { export interface EnvConfig {
commonParams?: EnvConfigItem; commonParams?: EnvConfigItem;
commmonVariables?: EnvConfigItem[]; commmonVariables: EnvConfigItem[];
httpConfig?: EnvConfigItem[]; httpConfig: EnvConfigItem[];
dataSource?: DataSourceItem[]; dataSources: DataSourceItem[];
hostConfig?: EnvConfigItem; hostConfig: EnvConfigItem;
authConfig?: EnvConfigItem; preProcessorConfig: ProcessorConfig;
preProcessorConfig?: EnvConfigItem; postProcessorConfig: ProcessorConfig;
postProcessorConfig?: EnvConfigItem; assertionConfig: EnvConfigItem[];
assertionConfig?: EnvConfigItem; pluginConfigMap: EnvConfigItem;
pluginConfigMap?: EnvConfigItem;
} }
export interface EnvDetailItem { export interface EnvDetailItem {
id?: string; id?: string;
@ -109,3 +113,13 @@ export interface DragParam {
moveMode: string; moveMode: string;
moveId: string; moveId: string;
} }
export interface HttpForm {
id?: string;
description?: string;
hostname: string;
enableCondition: string;
path: string;
operator: string;
headerParams: any[];
}

View File

@ -10,16 +10,42 @@ import { ContentTabItem, ContentTabsMap, EnvDetailItem, GlobalParams } from '@/m
export const ALL_PARAM = 'allParam'; export const ALL_PARAM = 'allParam';
export const NEW_ENV_PARAM = 'newEnvParam'; export const NEW_ENV_PARAM = 'newEnvParam';
export const NEW_ENV_GROUP = 'newEnvGroup'; export const NEW_ENV_GROUP = 'newEnvGroup';
const envParmasDefaultConfig = {
commmonVariables: [],
httpConfig: [],
dataSources: [],
hostConfig: {
enable: false,
hosts: [],
},
preProcessorConfig: {
apiProcessorConfig: [],
},
postProcessorConfig: {
apiProcessorConfig: [],
},
assertionConfig: [],
pluginConfigMap: {},
};
const useProjectEnvStore = defineStore( const useProjectEnvStore = defineStore(
'projectEnv', 'projectEnv',
() => { () => {
// 项目中的key值 // 项目中的key值
const currentId = ref<string>('1052215449649153'); const currentId = ref<string>('');
// 项目组选中的key值 // 项目组选中的key值
const currentGroupId = ref<string>(''); const currentGroupId = ref<string>('');
const currentEnvDetailInfo = ref<EnvDetailItem>({ projectId: '', name: '', config: {} }); // 当前选中的环境详情 // 当前选中的环境详情
const backupEnvDetailInfo = ref<EnvDetailItem>({ projectId: '', name: '', config: {} }); // 当前选中的环境详情-备份 const currentEnvDetailInfo = ref<EnvDetailItem>({
projectId: '',
name: '',
config: envParmasDefaultConfig,
});
const backupEnvDetailInfo = ref<EnvDetailItem>({
projectId: '',
name: '',
config: envParmasDefaultConfig,
});
const allParamDetailInfo = ref<GlobalParams>(); // 全局参数详情 const allParamDetailInfo = ref<GlobalParams>(); // 全局参数详情
const httpNoWarning = ref(true); const httpNoWarning = ref(true);
const getHttpNoWarning = computed(() => httpNoWarning.value); const getHttpNoWarning = computed(() => httpNoWarning.value);
@ -46,14 +72,22 @@ const useProjectEnvStore = defineStore(
const appStore = useAppStore(); const appStore = useAppStore();
try { try {
if (id === NEW_ENV_PARAM) { if (id === NEW_ENV_PARAM) {
currentEnvDetailInfo.value = { projectId: appStore.currentProjectId, name: '', config: {} }; currentEnvDetailInfo.value = {
backupEnvDetailInfo.value = { projectId: appStore.currentProjectId, name: '', config: {} }; projectId: appStore.currentProjectId,
name: '',
config: envParmasDefaultConfig,
};
backupEnvDetailInfo.value = {
projectId: appStore.currentProjectId,
name: '',
config: envParmasDefaultConfig,
};
} else if (id === ALL_PARAM) { } else if (id === ALL_PARAM) {
allParamDetailInfo.value = await getGlobalParamDetail(appStore.currentProjectId); allParamDetailInfo.value = await getGlobalParamDetail(appStore.currentProjectId);
} else if (id !== ALL_PARAM && id) { } else if (id !== ALL_PARAM && id) {
const tmpObj = await getDetailEnv(id); const tmpObj = await getDetailEnv(id);
currentEnvDetailInfo.value = tmpObj; currentEnvDetailInfo.value = tmpObj;
backupEnvDetailInfo.value = JSON.parse(JSON.stringify(tmpObj)); backupEnvDetailInfo.value = tmpObj;
} }
} catch (e) { } catch (e) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console

View File

@ -209,7 +209,7 @@
/> />
</div> </div>
</template> </template>
<template #tag="{ record, columnConfig, rowIndex }"> <template #tag="{ record, columnConfig }">
<a-popover <a-popover
position="tl" position="tl"
:disabled="record[columnConfig.dataIndex as string].length === 0" :disabled="record[columnConfig.dataIndex as string].length === 0"
@ -228,7 +228,6 @@
:max-tag-count="1" :max-tag-count="1"
input-class="param-input" input-class="param-input"
size="mini" size="mini"
@change="() => addTableLine(rowIndex)"
/> />
</a-popover> </a-popover>
</template> </template>

View File

@ -42,7 +42,7 @@
import MsUpload from '@/components/pure/ms-upload/index.vue'; import MsUpload from '@/components/pure/ms-upload/index.vue';
import { importGlobalParam } from '@/api/modules/project-management/envManagement'; import { importEnv, importGlobalParam } from '@/api/modules/project-management/envManagement';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import { EnvAuthTypeEnum } from '@/enums/envEnum'; import { EnvAuthTypeEnum } from '@/enums/envEnum';
@ -73,10 +73,14 @@
try { try {
confirmLoading.value = true; confirmLoading.value = true;
const params = { const params = {
request: null, request: {},
fileList: fileList.value, fileList: fileList.value,
}; };
if (props.type === EnvAuthTypeEnum.GLOBAL) {
await importGlobalParam(params); await importGlobalParam(params);
} else if (props.type === EnvAuthTypeEnum.ENVIRONMENT) {
await importEnv(params);
}
Message.success(t('common.importSuccess')); Message.success(t('common.importSuccess'));
handleCancel(true); handleCancel(true);
} catch (error) { } catch (error) {

View File

@ -3,7 +3,6 @@
<a-button type="outline" @click="handleAdd">{{ t('project.environmental.database.addDatabase') }}</a-button> <a-button type="outline" @click="handleAdd">{{ t('project.environmental.database.addDatabase') }}</a-button>
<a-input-search <a-input-search
v-model="keyword" v-model="keyword"
:placeholder="t('system.user.searchUser')"
class="w-[240px]" class="w-[240px]"
allow-clear allow-clear
@press-enter="fetchData" @press-enter="fetchData"
@ -23,9 +22,10 @@
</MsBaseTable> </MsBaseTable>
<AddDatabaseModal <AddDatabaseModal
v-model:visible="addVisible" v-model:visible="addVisible"
v-model="currentDatabase" :current-database="currentDatabase"
:current-id="currentId" :current-id="currentId"
@close="addVisible = false" @close="addVisible = false"
@add-or-update="handleAddOrUpdate"
/> />
</template> </template>
@ -34,7 +34,7 @@
import MsButton from '@/components/pure/ms-button/index.vue'; import MsButton from '@/components/pure/ms-button/index.vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue'; import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import { MsTableColumn } from '@/components/pure/ms-table/type'; import { MsTableColumn, MsTableDataItem } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable'; import useTable from '@/components/pure/ms-table/useTable';
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue'; import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
import { ActionsItem } from '@/components/pure/ms-table-more-action/types'; import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
@ -45,18 +45,15 @@
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore'; import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
import { BugListItem } from '@/models/bug-management'; import { BugListItem } from '@/models/bug-management';
import { CommonList } from '@/models/common';
import { DataSourceItem } from '@/models/projectManagement/environmental'; import { DataSourceItem } from '@/models/projectManagement/environmental';
import { TableKeyEnum } from '@/enums/tableEnum'; import { TableKeyEnum } from '@/enums/tableEnum';
const { t } = useI18n(); const { t } = useI18n();
const store = useProjectEnvStore(); const store = useProjectEnvStore();
const innerParam = computed({ const innerParam = computed(() => store.currentEnvDetailInfo.config.dataSources || []);
get: () => (store.currentEnvDetailInfo.config.dataSource || []) as DataSourceItem[],
set: (value: DataSourceItem[] | undefined) => {
store.currentEnvDetailInfo.config.dataSource = value;
},
});
const keyword = ref(''); const keyword = ref('');
const tableStore = useTableStore(); const tableStore = useTableStore();
const addVisible = ref(false); const addVisible = ref(false);
@ -121,15 +118,21 @@
}, },
]; ];
await tableStore.initColumn(TableKeyEnum.PROJECT_MANAGEMENT_ENV_ENV_HTTP, columns); await tableStore.initColumn(TableKeyEnum.PROJECT_MANAGEMENT_ENV_ENV_HTTP, columns);
const { propsRes, propsEvent } = useTable(undefined, { const { propsRes, propsEvent } = useTable(
() =>
Promise.resolve([]) as unknown as Promise<
MsTableDataItem<DataSourceItem> | CommonList<MsTableDataItem<DataSourceItem>>
>,
{
tableKey: TableKeyEnum.PROJECT_MANAGEMENT_ENV_ENV_HTTP, tableKey: TableKeyEnum.PROJECT_MANAGEMENT_ENV_ENV_HTTP,
scroll: { x: '100%' }, scroll: { x: '100%' },
selectable: false, selectable: false,
noDisable: true,
showSetting: true, showSetting: true,
showPagination: false, showPagination: false,
showMode: false, showMode: false,
}); isSimpleSetting: true,
}
);
const moreActionList: ActionsItem[] = [ const moreActionList: ActionsItem[] = [
{ {
@ -140,7 +143,10 @@
]; ];
const handleSingleDelete = (record?: TableData) => { const handleSingleDelete = (record?: TableData) => {
console.log('handleSingleDelete', record); if (record) {
const index = innerParam.value.findIndex((item) => item.id === record.id);
innerParam.value.splice(index, 1);
}
}; };
function handleMoreActionSelect(item: ActionsItem, record: BugListItem) { function handleMoreActionSelect(item: ActionsItem, record: BugListItem) {
@ -150,22 +156,37 @@
} }
const handleCopy = (record: any) => { const handleCopy = (record: any) => {
console.log('handleCopy', record); addVisible.value = true;
currentId.value = '';
currentDatabase.value = { ...record, id: '' };
}; };
const handleEdit = (record: any) => { const handleEdit = (record: any) => {
addVisible.value = true; addVisible.value = true;
currentId.value = record.id; currentId.value = record.id;
}; };
const handleAdd = () => { const handleAdd = () => {
currentDatabase.value = { name: '', dbUrl: '', username: '' };
addVisible.value = true; addVisible.value = true;
}; };
const fetchData = () => {}; const fetchData = () => {
const initData = () => { if (keyword.value) {
propsRes.value.data = innerParam.value.filter((item) => item.name.includes(keyword.value));
} else {
propsRes.value.data = innerParam.value; propsRes.value.data = innerParam.value;
}
}; };
onMounted(() => { const handleAddOrUpdate = (data: DataSourceItem, cb: (v: boolean) => void) => {
initData(); if (data.id) {
const index = innerParam.value.findIndex((item) => item.id === data.id);
store.currentEnvDetailInfo.config.dataSources[index] = data;
} else {
data.id = new Date().getTime().toString();
store.currentEnvDetailInfo.config.dataSources.push(data);
}
cb(true);
};
watch(innerParam.value, () => {
fetchData();
}); });
</script> </script>

View File

@ -28,7 +28,6 @@
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore'; import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
import { EnvConfigItem } from '@/models/projectManagement/environmental'; import { EnvConfigItem } from '@/models/projectManagement/environmental';
import { FakeTableListItem } from '@/models/projectManagement/menuManagement';
const { t } = useI18n(); const { t } = useI18n();
@ -37,7 +36,6 @@
const currentList = computed({ const currentList = computed({
get: () => store.currentEnvDetailInfo.config.hostConfig || {}, get: () => store.currentEnvDetailInfo.config.hostConfig || {},
set: (value: EnvConfigItem) => { set: (value: EnvConfigItem) => {
console.log(value);
store.currentEnvDetailInfo.config.hostConfig = value || {}; store.currentEnvDetailInfo.config.hostConfig = value || {};
}, },
}); });

View File

@ -39,7 +39,7 @@
</div> </div>
</template> </template>
</MsBaseTable> </MsBaseTable>
<AddHttpDrawer v-model:visible="addVisible" :current-id="currentId" @close="addVisible = false" /> <AddHttpDrawer v-model:visible="addVisible" :current-obj="currentObj" @close="addVisible = false" />
</template> </template>
<script lang="ts" async setup> <script lang="ts" async setup>
@ -58,6 +58,7 @@
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore'; import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
import { BugListItem } from '@/models/bug-management'; import { BugListItem } from '@/models/bug-management';
import { HttpForm } from '@/models/projectManagement/environmental';
import { TableKeyEnum } from '@/enums/tableEnum'; import { TableKeyEnum } from '@/enums/tableEnum';
const { t } = useI18n(); const { t } = useI18n();
@ -67,15 +68,14 @@
const showTitle = computed(() => store.httpNoWarning); const showTitle = computed(() => store.httpNoWarning);
const tableStore = useTableStore(); const tableStore = useTableStore();
const addVisible = ref(false); const addVisible = ref(false);
const currentId = ref(''); const currentObj = ref<HttpForm>({
id: '',
const innerParam = computed({ hostname: '',
set: (value: TableData[]) => { enableCondition: 'none',
store.currentEnvDetailInfo.config.httpConfig = value; path: '',
}, operator: '',
get: () => store.currentEnvDetailInfo.config.httpConfig || [], headerParams: [],
}); });
const columns: MsTableColumn = [ const columns: MsTableColumn = [
{ {
title: 'project.environmental.http.host', title: 'project.environmental.http.host',
@ -144,7 +144,12 @@
]; ];
const handleSingleDelete = (record?: TableData) => { const handleSingleDelete = (record?: TableData) => {
console.log('handleSingleDelete', record); if (record) {
const index = store.currentEnvDetailInfo.config.httpConfig.findIndex((item) => item.id === record.id);
if (index > -1) {
store.currentEnvDetailInfo.config.httpConfig.splice(index, 1);
}
}
}; };
function handleMoreActionSelect(item: ActionsItem, record: BugListItem) { function handleMoreActionSelect(item: ActionsItem, record: BugListItem) {
@ -152,26 +157,32 @@
handleSingleDelete(record); handleSingleDelete(record);
} }
} }
const handleCopy = (record: any) => { const handleCopy = (record: any) => {
console.log('handleCopy', record); currentObj.value = record;
currentObj.value.id = '';
addVisible.value = true;
}; };
const handleEdit = (record: any) => { const handleEdit = (record: any) => {
currentObj.value = record;
addVisible.value = true; addVisible.value = true;
currentId.value = record.id;
}; };
const handleAddHttp = () => { const handleAddHttp = () => {
currentObj.value = {
id: '',
hostname: '',
enableCondition: 'none',
path: '',
operator: '',
headerParams: [],
};
addVisible.value = true; addVisible.value = true;
}; };
const handleNoWarning = () => { const handleNoWarning = () => {
store.setHttpNoWarning(false); store.setHttpNoWarning(false);
}; };
const initData = () => { watch(store.currentEnvDetailInfo.config.httpConfig, () => {
propsRes.value.data = innerParam.value; propsRes.value.data = store.currentEnvDetailInfo.config.httpConfig;
};
onMounted(() => {
initData();
}); });
</script> </script>

View File

@ -1,20 +1,27 @@
<template> <template>
<PostTab v-model:config="params" layout="horizontal" /> <condition
v-model:list="innerParams"
:condition-types="[RequestConditionProcessor.SCRIPT, RequestConditionProcessor.SQL]"
add-text="apiTestDebug.postCondition"
response=""
:height-used="600"
>
</condition>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import PostTab from '@/views/api-test/components/requestComposition/postcondition.vue'; import condition from '@/views/api-test/components/condition/index.vue';
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore'; import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
const store = useProjectEnvStore(); import { RequestConditionProcessor } from '@/enums/apiEnum';
// TODO: const store = useProjectEnvStore();
const params = computed<any>({ const innerParams = computed({
set: (value: any) => { set: (value: any) => {
store.currentEnvDetailInfo.config.postProcessorConfig = value; store.currentEnvDetailInfo.config.postProcessorConfig.apiProcessorConfig = value || [];
}, },
get: () => store.currentEnvDetailInfo.config.postProcessorConfig || {}, get: () => store.currentEnvDetailInfo.config.postProcessorConfig.apiProcessorConfig || [],
}); });
</script> </script>

View File

@ -1,20 +1,27 @@
<template> <template>
<PreTab v-model:config="params" layout="horizontal" /> <condition
v-model:list="innerParams"
:condition-types="[RequestConditionProcessor.SCRIPT, RequestConditionProcessor.SQL]"
add-text="apiTestDebug.precondition"
response=""
:height-used="600"
>
</condition>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import PreTab from '@/views/api-test/components/requestComposition/precondition.vue'; import condition from '@/views/api-test/components/condition/index.vue';
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore'; import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
const store = useProjectEnvStore(); import { RequestConditionProcessor } from '@/enums/apiEnum';
// TODO: const store = useProjectEnvStore();
const params = computed<any>({ const innerParams = computed({
set: (value: any) => { set: (value: any) => {
store.currentEnvDetailInfo.config.preProcessorConfig = value; store.currentEnvDetailInfo.config.preProcessorConfig.apiProcessorConfig = value || [];
}, },
get: () => store.currentEnvDetailInfo.config.preProcessorConfig || {}, get: () => store.currentEnvDetailInfo.config.preProcessorConfig.apiProcessorConfig || [],
}); });
</script> </script>

View File

@ -1,5 +1,12 @@
<template> <template>
<MsDrawer :width="891" :visible="visible" unmount-on-close :mask="false" @cancel="emit('close')"> <MsDrawer
:width="891"
:visible="visible"
unmount-on-close
:mask="false"
@confirm="handleAddOrUpdate"
@cancel="emit('close')"
>
<template #title> <template #title>
<div>{{ title }}</div> <div>{{ title }}</div>
</template> </template>
@ -22,12 +29,6 @@
</template> </template>
</a-input> </a-input>
</a-form-item> </a-form-item>
<a-form-item class="mb-[16px]" field="applyModule" :label="t('project.environmental.http.applyModule')">
<a-checkbox-group v-model="form.applyModule">
<a-checkbox value="apiTest">{{ t('menu.apiTest') }}</a-checkbox>
<a-checkbox value="uiTest">{{ t('menu.uiTest') }}</a-checkbox>
</a-checkbox-group>
</a-form-item>
<a-form-item class="mb-[16px]" field="enableCondition" :label="t('project.environmental.http.enableCondition')"> <a-form-item class="mb-[16px]" field="enableCondition" :label="t('project.environmental.http.enableCondition')">
<a-select v-model:model-value="form.enableCondition"> <a-select v-model:model-value="form.enableCondition">
<a-option value="none">{{ t('project.environmental.http.none') }}</a-option> <a-option value="none">{{ t('project.environmental.http.none') }}</a-option>
@ -36,7 +37,7 @@
</a-select> </a-select>
</a-form-item> </a-form-item>
<!-- 接口模块选择 --> <!-- 接口模块选择 -->
<a-form-item <!-- <a-form-item
v-if="showApiModule" v-if="showApiModule"
class="mb-[16px]" class="mb-[16px]"
field="apiModule" field="apiModule"
@ -47,9 +48,12 @@
<a-select v-model:model-value="form.apiModule" multiple :placeholder="t('common.pleaseSelect')"> <a-select v-model:model-value="form.apiModule" multiple :placeholder="t('common.pleaseSelect')">
<a-option value="none">{{ t('project.environmental.http.none') }}</a-option> <a-option value="none">{{ t('project.environmental.http.none') }}</a-option>
</a-select> </a-select>
</a-form-item> -->
<a-form-item class="mb-[16px]" field="description" :label="t('project.environmental.http.description')">
<a-input />
</a-form-item> </a-form-item>
<!-- 选择UI测试模块 --> <!-- 选择UI测试模块 -->
<a-form-item <!-- <a-form-item
v-if="showUIModule" v-if="showUIModule"
class="mb-[16px]" class="mb-[16px]"
field="enableCondition" field="enableCondition"
@ -60,7 +64,7 @@
<a-select v-model:model-value="form.uiModule" multiple :placeholder="t('common.pleaseSelect')"> <a-select v-model:model-value="form.uiModule" multiple :placeholder="t('common.pleaseSelect')">
<a-option value="none">{{ t('project.environmental.http.none') }}</a-option> <a-option value="none">{{ t('project.environmental.http.none') }}</a-option>
</a-select> </a-select>
</a-form-item> </a-form-item> -->
<!-- 路径 --> <!-- 路径 -->
<a-form-item <a-form-item
v-if="showPathInput" v-if="showPathInput"
@ -88,7 +92,7 @@
</a-input> </a-input>
</a-form-item> </a-form-item>
</a-form> </a-form>
<RequestHeader :params="headerParams" /> <RequestHeader :params="form.headerParams" />
</MsDrawer> </MsDrawer>
</template> </template>
@ -100,57 +104,51 @@
import RequestHeader from '../../requestHeader/index.vue'; import RequestHeader from '../../requestHeader/index.vue';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
import { HttpForm } from '@/models/projectManagement/environmental';
const props = defineProps<{ const props = defineProps<{
currentId?: string; currentObj: HttpForm;
}>(); }>();
const store = useProjectEnvStore();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'close'): void; (e: 'close'): void;
}>(); }>();
const form = reactive<{ const form = ref<HttpForm>({
hostname: string; id: '',
applyModule: string[];
enableCondition: string;
apiModule: string[];
uiModule: string[];
path: string;
operator: string;
}>({
hostname: '', hostname: '',
applyModule: [],
enableCondition: 'none', enableCondition: 'none',
apiModule: [],
uiModule: [],
path: '', path: '',
operator: '', operator: '',
headerParams: [],
}); });
const httpRef = ref(); const httpRef = ref();
const showApiModule = computed(() => form.enableCondition === 'module' && form.applyModule.includes('apiTest')); const showPathInput = computed(() => form.value.enableCondition === 'path');
const showUIModule = computed(() => form.enableCondition === 'module' && form.applyModule.includes('uiTest'));
const showPathInput = computed(() => form.enableCondition === 'path');
const headerParams = ref<[]>([]);
const visible = defineModel('visible', { required: true, type: Boolean, default: false }); const visible = defineModel('visible', { required: true, type: Boolean, default: false });
const { t } = useI18n(); const { t } = useI18n();
const isEdit = computed(() => !!props.currentId); const isEdit = computed(() => !!props.currentObj.id);
const title = computed(() => { const title = computed(() => {
return isEdit.value ? t('project.environmental.http.edit') : t('project.environmental.http.add'); return isEdit.value ? t('project.environmental.http.edit') : t('project.environmental.http.add');
}); });
watchEffect(() => { const handleAddOrUpdate = () => {
if (showApiModule.value) { if (form.value.id) {
form.apiModule = []; const index = store.currentEnvDetailInfo.config.httpConfig.findIndex((item) => item.id === form.value.id);
store.currentEnvDetailInfo.config.httpConfig.splice(index, 1, form.value);
} else {
store.currentEnvDetailInfo.config.httpConfig.push(form);
} }
if (showUIModule.value) { emit('close');
form.uiModule = []; };
}
});
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -24,7 +24,12 @@
asterisk-position="end" asterisk-position="end"
:rules="[{ required: true, message: t('project.environmental.database.nameIsRequire') }]" :rules="[{ required: true, message: t('project.environmental.database.nameIsRequire') }]"
> >
<a-input v-model="form.name" allow-clear :placeholder="t('project.environmental.database.namePlaceholder')" /> <a-input
v-model="form.name"
:max-length="255"
allow-clear
:placeholder="t('project.environmental.database.namePlaceholder')"
/>
</a-form-item> </a-form-item>
<a-form-item field="driverId" asterisk-position="end" :label="t('project.environmental.database.driver')"> <a-form-item field="driverId" asterisk-position="end" :label="t('project.environmental.database.driver')">
<a-select v-model="form.driverId" :options="driverOption" /> <a-select v-model="form.driverId" :options="driverOption" />
@ -37,7 +42,7 @@
:extra="t('project.environmental.database.urlExtra')" :extra="t('project.environmental.database.urlExtra')"
:rules="[{ required: true, message: t('project.environmental.database.urlIsRequire') }]" :rules="[{ required: true, message: t('project.environmental.database.urlIsRequire') }]"
> >
<a-input v-model="form.dbUrl" allow-clear :placeholder="t('common.pleaseInput')" /> <a-input v-model="form.dbUrl" :max-length="255" allow-clear :placeholder="t('common.pleaseInput')" />
</a-form-item> </a-form-item>
<a-form-item <a-form-item
field="username" field="username"
@ -111,7 +116,7 @@
const { t } = useI18n(); const { t } = useI18n();
const props = defineProps<{ const props = defineProps<{
modelValue: DataSourceItem; currentDatabase: DataSourceItem;
visible: boolean; visible: boolean;
}>(); }>();
@ -124,6 +129,7 @@
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'cancel', shouldSearch: boolean): void; (e: 'cancel', shouldSearch: boolean): void;
(e: 'addOrUpdate', data: DataSourceItem, cb: (v: boolean) => void): void;
}>(); }>();
const currentVisible = defineModel('visible', { const currentVisible = defineModel('visible', {
@ -131,11 +137,19 @@
type: Boolean, type: Boolean,
}); });
const form = defineModel<DataSourceItem>('modelValue', { const form = ref<DataSourceItem>({
required: true, id: '',
name: '',
driverId: '',
dbUrl: '',
username: '',
password: '',
poolMax: 1,
timeout: 1000,
enable: true,
}); });
const isEdit = computed(() => form.value.id); const isEdit = computed(() => !!props.currentDatabase.id);
const getDriverOption = async () => { const getDriverOption = async () => {
try { try {
@ -188,7 +202,6 @@
}); });
const formReset = () => { const formReset = () => {
if (!isEdit.value) {
form.value = { form.value = {
id: '', id: '',
name: '', name: '',
@ -200,7 +213,6 @@
timeout: 1000, timeout: 1000,
enable: true, enable: true,
}; };
}
}; };
const handleCancel = (shouldSearch: boolean) => { const handleCancel = (shouldSearch: boolean) => {
emit('cancel', shouldSearch); emit('cancel', shouldSearch);
@ -215,13 +227,14 @@
} }
try { try {
loading.value = true; loading.value = true;
emit('addOrUpdate', form.value, (v: boolean) => {
Message.success( Message.success(
isEdit.value isEdit.value
? t('project.environmental.database.updateProjectSuccess') ? t('project.environmental.database.updateDataSourceSuccess')
: t('project.environmental.database.createProjectSuccess') : t('project.environmental.database.createDataSourceSuccess')
); );
handleCancel(true); handleCancel(v);
});
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.error(error); console.error(error);
@ -234,8 +247,15 @@
getDriverOption(); getDriverOption();
}; };
watchEffect(() => { watchEffect(() => {
if (props.visible) {
initData(); initData();
if (props.currentDatabase?.id) {
//
if (props.currentDatabase) {
form.value = { ...props.currentDatabase };
}
} else {
//
formReset();
} }
}); });
</script> </script>

View File

@ -186,12 +186,22 @@
</MsSplitBox> </MsSplitBox>
</div> </div>
<CommonImportPop v-model:visible="importVisible" :type="importAuthType" @submit="handleSubmit" /> <CommonImportPop v-model:visible="importVisible" :type="importAuthType" @submit="handleSubmit" />
<MsExportDrawer
v-model:visible="envExportVisible"
:all-data="exportOptionData"
:default-selected-keys="[]"
is-array-column
:array-column="envList"
@confirm="(v) => handleEnvExport(v.map((item) => item.id))"
/>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { VueDraggable } from 'vue-draggable-plus'; import { VueDraggable } from 'vue-draggable-plus';
import MsButton from '@/components/pure/ms-button/index.vue'; import MsButton from '@/components/pure/ms-button/index.vue';
import MsExportDrawer from '@/components/pure/ms-export-drawer/index.vue';
import { MsExportDrawerMap } from '@/components/pure/ms-export-drawer/types';
import MsIcon from '@/components/pure/ms-icon-font/index.vue'; import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import MsSplitBox from '@/components/pure/ms-split-box/index.vue'; import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
import MsMoreAction from '@/components/pure/ms-table-more-action/index.vue'; import MsMoreAction from '@/components/pure/ms-table-more-action/index.vue';
@ -203,7 +213,9 @@
import RenamePop from './components/RenamePop.vue'; import RenamePop from './components/RenamePop.vue';
import { import {
deleteEnv,
deleteEnvGroup, deleteEnvGroup,
exportEnv,
exportGlobalParam, exportGlobalParam,
groupEditPosEnv, groupEditPosEnv,
groupListEnv, groupListEnv,
@ -247,6 +259,12 @@
const importVisible = ref<boolean>(false); const importVisible = ref<boolean>(false);
// //
const importAuthType = ref<EnvAuthTypeEnum>(EnvAuthTypeEnum.GLOBAL); const importAuthType = ref<EnvAuthTypeEnum>(EnvAuthTypeEnum.GLOBAL);
// Drawer
const envExportVisible = ref<boolean>(false);
// option
const exportOptionData = ref<MsExportDrawerMap>({
systemColumns: {},
});
// MoreAction // MoreAction
const envMoreAction: ActionsItem[] = [ const envMoreAction: ActionsItem[] = [
@ -301,6 +319,16 @@
console.log(error); console.log(error);
} }
}; };
//
const handleEnvExport = async (id: string | string[]) => {
try {
const blob = await exportEnv(Array.isArray(id) ? id : [id]);
downloadByteFile(blob, 'EnvParam.json');
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
};
const handleSubmit = (shouldSearch: boolean) => { const handleSubmit = (shouldSearch: boolean) => {
if (shouldSearch) { if (shouldSearch) {
@ -312,7 +340,10 @@
} }
}; };
// //
const handleEnvImport = () => {}; const handleEnvImport = () => {
importVisible.value = true;
importAuthType.value = EnvAuthTypeEnum.ENVIRONMENT;
};
// //
const handleCreateEnv = () => { const handleCreateEnv = () => {
@ -370,17 +401,6 @@
} }
}; };
//
const handleDeleteEnvGroup = async (id: string) => {
try {
await deleteEnvGroup(id);
await initGroupList();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
};
const initData = async (keywordStr = '') => { const initData = async (keywordStr = '') => {
try { try {
envList.value = await listEnv({ projectId: appStore.currentProjectId, keyword: keywordStr }); envList.value = await listEnv({ projectId: appStore.currentProjectId, keyword: keywordStr });
@ -393,6 +413,35 @@
} }
}; };
function searchData() {
initData(keyword.value);
}
//
const handleDeleteEnv = async (id: string) => {
try {
await deleteEnv(id);
if (store.currentId === id) {
store.setCurrentId('');
}
searchData();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
};
//
const handleDeleteEnvGroup = async (id: string) => {
try {
await deleteEnvGroup(id);
await initGroupList();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
};
function changeShowType(value: string | number | boolean) { function changeShowType(value: string | number | boolean) {
if (value === 'PROJECT_GROUP') { if (value === 'PROJECT_GROUP') {
initGroupList(); initGroupList();
@ -424,25 +473,26 @@
store.setCurrentGroupId(id); store.setCurrentGroupId(id);
}; };
function searchData() {
initData(keyword.value);
}
// MoreAction // MoreAction
const handleMoreAction = (item: ActionsItem, id: string, scopeType: EnvAuthTypeEnum) => { const handleMoreAction = (item: ActionsItem, id: string, scopeType: EnvAuthTypeEnum) => {
const { eventTag } = item; const { eventTag } = item;
switch (eventTag) { switch (eventTag) {
case 'export': case 'export':
if (scopeType === EnvAuthTypeEnum.GLOBAL) { if (scopeType === EnvAuthTypeEnum.GLOBAL) {
//
handleGlobalExport(); handleGlobalExport();
} else if (scopeType === EnvAuthTypeEnum.ENVIRONMENT) {
handleEnvImport();
} else if (scopeType === EnvAuthTypeEnum.ENVIRONMENT_PARAM) { } else if (scopeType === EnvAuthTypeEnum.ENVIRONMENT_PARAM) {
handleEnvImport(); //
handleEnvExport(id);
} else if (scopeType === EnvAuthTypeEnum.ENVIRONMENT) {
envExportVisible.value = true;
} }
break; break;
case 'delete': case 'delete':
if (scopeType === EnvAuthTypeEnum.ENVIRONMENT_GROUP) { if (scopeType === EnvAuthTypeEnum.ENVIRONMENT_GROUP) {
handleDeleteEnvGroup(id); handleDeleteEnvGroup(id);
} else if (scopeType === EnvAuthTypeEnum.ENVIRONMENT_PARAM) {
handleDeleteEnv(id);
} }
break; break;
case 'import': case 'import':
@ -495,7 +545,9 @@
.env-row { .env-row {
@apply flex flex-row justify-between; @apply flex flex-row justify-between;
&-extra { &-extra {
@apply relative hidden; @apply relative;
opacity: 0;
} }
&:hover { &:hover {
.env-row-extra { .env-row-extra {

View File

@ -62,8 +62,12 @@ export default {
'project.environmental.http.uiModuleSelect': '选择UI测试模块', 'project.environmental.http.uiModuleSelect': '选择UI测试模块',
'project.environmental.http.pathRequired': '路径必填', 'project.environmental.http.pathRequired': '路径必填',
'project.environmental.http.pathPlaceholder': '请输入路径', 'project.environmental.http.pathPlaceholder': '请输入路径',
'project.environmental.http.description': '描述',
'project.environmental.database.title': '数据库',
'project.environmental.database.addDatabase': '添加数据源', 'project.environmental.database.addDatabase': '添加数据源',
'project.environmental.database.updateDatabase': '更新数据源{name}', 'project.environmental.database.updateDatabase': '更新数据源{name}',
'project.environmental.database.updateDataSourceSuccess': '更新数据源成功',
'project.environmental.database.createDataSourceSuccess': '创建数据源成功',
'project.environmental.database.name': '数据源名称', 'project.environmental.database.name': '数据源名称',
'project.environmental.database.nameIsRequire': '数据源名称不能为空', 'project.environmental.database.nameIsRequire': '数据源名称不能为空',
'project.environmental.database.namePlaceholder': '请输入数据源名称', 'project.environmental.database.namePlaceholder': '请输入数据源名称',
@ -77,6 +81,7 @@ export default {
'project.environmental.database.urlExtra': '执行多条 SQL 语句需配置 allowMultiQueries=true', 'project.environmental.database.urlExtra': '执行多条 SQL 语句需配置 allowMultiQueries=true',
'project.environmental.database.urlIsRequire': '数据库连接 URL 必填', 'project.environmental.database.urlIsRequire': '数据库连接 URL 必填',
'project.environmental.database.testConnection': '测试连接', 'project.environmental.database.testConnection': '测试连接',
'project.environmental.database.testConnectionSuccess': '连接成功',
'project.environmental.host.config': 'Host 配置', 'project.environmental.host.config': 'Host 配置',
'project.environmental.host.ip': 'IP', 'project.environmental.host.ip': 'IP',
'project.environmental.host.ipPlaceholder': '请输入 IP 地址', 'project.environmental.host.ipPlaceholder': '请输入 IP 地址',