This commit is contained in:
liqiang-fit2cloud 2023-01-06 18:08:04 +08:00
commit 93b8bbdce5
10 changed files with 227 additions and 123 deletions

View File

@ -187,6 +187,13 @@ public class MockConfigService {
}
}
public void sendMockNotice(String mockExpectId, String defaultContext, String event) {
MockExpectConfigWithBLOBs mockExpectConfigWithBLOBs = mockExpectConfigMapper.selectByPrimaryKey(mockExpectId);
if (mockExpectConfigWithBLOBs != null) {
this.sendMockNotice(mockExpectConfigWithBLOBs, defaultContext, event);
}
}
private void getParamMap(Map<String, Object> paramMap, String userId, MockExpectConfigWithBLOBs mockExpectConfigWithBLOBs, MockConfig mockConfig) {
paramMap.put("operator", userId);
paramMap.put("id", mockExpectConfigWithBLOBs.getId());
@ -213,7 +220,7 @@ public class MockConfigService {
model.setUpdateTime(timestamp);
model.setStatus(request.getStatus());
mockExpectConfigMapper.updateByPrimaryKeySelective(model);
sendMockNotice(model, "更新了mock", NoticeConstants.Event.MOCK_UPDATE);
sendMockNotice(request.getId(), "更新了mock", NoticeConstants.Event.MOCK_UPDATE);
return model;
} else {
return null;

View File

@ -1463,7 +1463,15 @@ public class ApiDefinitionService {
}
public List<ApiDefinitionWithBLOBs> preparedUrl(String projectId, String method, String baseUrlSuffix, String mockApiResourceId) {
if (StringUtils.isEmpty(baseUrlSuffix)) {
if (StringUtils.isNotBlank(mockApiResourceId)) {
//如果请求头中指定了API 则返回当前API
List<ApiDefinitionWithBLOBs> returnList = new ArrayList<>();
ApiDefinitionWithBLOBs apiDefinition = apiDefinitionMapper.selectByPrimaryKey(mockApiResourceId);
if (apiDefinition != null) {
returnList.add(apiDefinition);
}
return returnList;
} else if (StringUtils.isEmpty(baseUrlSuffix)) {
return new ArrayList<>();
} else {
String apiId = this.getApiIdFromMockApiResourceId(mockApiResourceId, projectId);
@ -2206,70 +2214,70 @@ public class ApiDefinitionService {
long timeStamp = System.currentTimeMillis();
MockConfigExample mockConfigExample = new MockConfigExample();
mockConfigExample.createCriteria().andApiIdIn(new ArrayList<>(sourceApiIdRefIdMap.keySet()));
List<MockConfig> mockConfigList = mockConfigMapper.selectByExample(mockConfigExample);
if (CollectionUtils.isNotEmpty(mockConfigList)) {
List<String> mockIdList = mockConfigList.stream().map(MockConfig::getId).collect(Collectors.toList());
List<MockConfig> sourceMockConfigList = mockConfigMapper.selectByExample(mockConfigExample);
if (CollectionUtils.isNotEmpty(sourceMockConfigList)) {
List<String> sourceMockConfigIdList = sourceMockConfigList.stream().map(MockConfig::getId).collect(Collectors.toList());
MockExpectConfigExample mockExpectConfigExample = new MockExpectConfigExample();
mockExpectConfigExample.createCriteria().andMockConfigIdIn(mockIdList);
mockExpectConfigExample.createCriteria().andMockConfigIdIn(sourceMockConfigIdList);
List<MockExpectConfigWithBLOBs> mockExpectConfigWithBLOBsList = mockExpectConfigMapper.selectByExampleWithBLOBs(mockExpectConfigExample);
Map<String, List<MockExpectConfigWithBLOBs>> mockConfigIdExpectMap = mockExpectConfigWithBLOBsList.stream().collect(Collectors.groupingBy(MockExpectConfigWithBLOBs::getMockConfigId));
Map<String, List<MockExpectConfigWithBLOBs>> sourceMockConfigIdMap = mockExpectConfigWithBLOBsList.stream().collect(Collectors.groupingBy(MockExpectConfigWithBLOBs::getMockConfigId));
List<MockConfig> saveMockList = new ArrayList<>();
List<MockExpectConfigWithBLOBs> saveMockExpectList = new ArrayList<>();
List<MockExpectConfigWithBLOBs> updateMockExpectList = new ArrayList<>();
mockConfigList.forEach(item -> {
String oldApiId = item.getApiId();
String refId = sourceApiIdRefIdMap.get(oldApiId);
sourceMockConfigList.forEach(item -> {
String sourceApiId = item.getApiId();
String refId = sourceApiIdRefIdMap.get(sourceApiId);
if (StringUtils.isNotBlank(refId)) {
ApiDefinition api = refIdMap.get(refId);
if (api != null) {
MockConfig baseMockConfig = mockConfigService.selectMockConfigByApiId(api.getId());
String mockConfigId = UUID.randomUUID().toString();
ApiDefinition goalApi = refIdMap.get(refId);
if (goalApi != null) {
MockConfig goalApiMockConfig = mockConfigService.selectMockConfigByApiId(goalApi.getId());
String goalApiMockConfigId = UUID.randomUUID().toString();
Map<String, MockExpectConfig> oldMockExpectConfig = new HashMap<>();
//已经存储的mock期望编号
List<String> saveExpectNumList = new ArrayList<>();
if (baseMockConfig == null) {
if (goalApiMockConfig == null) {
MockConfig mockConfig = new MockConfig();
BeanUtils.copyBean(mockConfig, item);
mockConfig.setApiId(api.getId());
mockConfig.setId(mockConfigId);
mockConfig.setApiId(goalApi.getId());
mockConfig.setId(goalApiMockConfigId);
mockConfig.setCreateTime(timeStamp);
mockConfig.setUpdateTime(timeStamp);
saveMockList.add(mockConfig);
} else {
mockConfigId = baseMockConfig.getId();
saveExpectNumList = mockConfigService.selectExpectNumberByConfigId(mockConfigId);
List<MockExpectConfig> oldMockExpectList = mockConfigService.selectSimpleMockExpectConfigByMockConfigId(mockConfigId);
oldMockExpectList.forEach(mockExpectConfig -> {
goalApiMockConfigId = goalApiMockConfig.getId();
saveExpectNumList = mockConfigService.selectExpectNumberByConfigId(goalApiMockConfigId);
List<MockExpectConfig> goalMockExpectList = mockConfigService.selectSimpleMockExpectConfigByMockConfigId(goalApiMockConfigId);
goalMockExpectList.forEach(mockExpectConfig -> {
oldMockExpectConfig.put(StringUtils.trim(mockExpectConfig.getName()), mockExpectConfig);
});
}
List<MockExpectConfigWithBLOBs> mockExpectConfigList = mockConfigIdExpectMap.get(item.getId());
List<MockExpectConfigWithBLOBs> mockExpectConfigList = sourceMockConfigIdMap.get(item.getId());
if (CollectionUtils.isNotEmpty(mockExpectConfigList)) {
String finalMockConfigId = mockConfigId;
String finalMockConfigId = goalApiMockConfigId;
List<String> finalSaveExpectNumList = saveExpectNumList;
mockExpectConfigList.forEach(mockExpectConfigWithBLOBs -> {
MockExpectConfig oldExpect = oldMockExpectConfig.get(StringUtils.trim(mockExpectConfigWithBLOBs.getName()));
MockExpectConfigWithBLOBs expectConfigWithBLOBs = new MockExpectConfigWithBLOBs();
BeanUtils.copyBean(expectConfigWithBLOBs, mockExpectConfigWithBLOBs);
expectConfigWithBLOBs.setMockConfigId(finalMockConfigId);
expectConfigWithBLOBs.setUpdateTime(timeStamp);
if (oldExpect == null) {
String newMockExpectNum = mockConfigService.getMockExpectId(String.valueOf(api.getNum()), finalSaveExpectNumList);
String newMockExpectNum = mockConfigService.getMockExpectId(String.valueOf(goalApi.getNum()), finalSaveExpectNumList);
finalSaveExpectNumList.add(newMockExpectNum);
expectConfigWithBLOBs.setId(UUID.randomUUID().toString());
expectConfigWithBLOBs.setExpectNum(newMockExpectNum);
expectConfigWithBLOBs.setCreateTime(timeStamp);
expectConfigWithBLOBs.setUpdateTime(timeStamp);
expectConfigWithBLOBs.setMockConfigId(finalMockConfigId);
saveMockExpectList.add(expectConfigWithBLOBs);
} else {
expectConfigWithBLOBs.setId(oldExpect.getId());
expectConfigWithBLOBs.setCreateTime(oldExpect.getCreateTime());
expectConfigWithBLOBs.setUpdateTime(timeStamp);
updateMockExpectList.add(expectConfigWithBLOBs);
}
});

View File

@ -1,86 +1,84 @@
<template>
<el-dialog
width="600px"
:visible.sync="batchSyncApiVisible" :close-on-click-modal="false"
:title="$t('commons.save') + '&' + $t('workstation.sync') + $t('commons.setting')"
v-if="isXpack">
<el-row style="margin-bottom: 10px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1)">
<div class="timeClass">
<span style="font-size: 16px; font-weight: bold; padding-left: 10px">{{
$t('api_test.definition.one_click_sync') + 'case'
}}</span>
<el-switch v-model="apiSyncRuleRelation.syncCase" style="float:right; padding-right: 10px"></el-switch>
<el-row class="box-class" style="margin-bottom: 16px;">
<div class="time-class">
<span>{{ $t('api_test.definition.one_click_sync') + 'case' }}</span>
<el-switch v-model="apiSyncRuleRelation.syncCase" style="float:right;"></el-switch>
</div>
<br/>
<span style="font-size: 12px; padding-left: 10px">{{ $t('workstation.batch_sync_api_tips') }}</span
><br/><br/>
<span v-if="apiSyncRuleRelation.syncCase" style="font-size: 16px; font-weight: bold; padding-left: 10px">
<span class="tip-class">{{ $t('workstation.batch_sync_api_tips') }}</span>
<div v-if="apiSyncRuleRelation.syncCase">
<div style="border-top: solid rgba(31, 35, 41, 0.15) 1px; margin: 16px 0;"></div>
<span class="time-class">
{{ $t('workstation.sync') + $t('commons.setting') }}
<i class="el-icon-arrow-down" v-if="showApiSyncConfig" @click="showApiSyncConfig = false"/>
<i class="el-icon-arrow-right" v-if="!showApiSyncConfig" @click="showApiSyncConfig = true"/> </span
><br/><br/>
<div v-if="showApiSyncConfig">
</span>
<sync-setting
style="padding-left: 20px"
v-if="apiSyncRuleRelation.syncCase"
style="margin-top: 16px"
v-bind:sync-data="apiSyncRuleRelation.apiSyncConfig"
ref="synSetting"
@updateSyncData="updateSyncData"></sync-setting>
</div>
</el-row>
<el-row style="margin-bottom: 10px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1)">
<div class="timeClass">
<span style="font-size: 16px; font-weight: bold; padding-left: 10px">
<el-row class="box-class" style="margin-bottom: 10px;">
<div class="time-class">
<div style="display: flex">
<span>
{{ $t('api_test.definition.change_notification') }}
</span>
<el-tooltip
class="ms-num"
effect="dark"
:content="$t('project_application.workstation.api_receiver_tip')"
placement="top">
<i class="el-icon-warning"/>
<svg-icon iconClass="question" class-name="ms-menu-img"
:style="{color:'#8F959E',margin: '4px 0 0 0'}"></svg-icon>
</el-tooltip>
</span>
<el-switch v-model="apiSyncRuleRelation.sendNotice" style="float:right;padding-right: 10px"></el-switch>
</div>
<span style="font-size: 12px; padding-left: 10px"> {{ $t('api_test.definition.recipient_tips') }} </span><br/>
<p
style="
font-size: 12px;
color: var(--primary_color);
margin-bottom: 20px;
text-decoration: underline;
cursor: pointer;
padding-left: 10px;
"
@click="gotoApiMessage">
<el-switch v-model="apiSyncRuleRelation.sendNotice" style="float:right;"></el-switch>
</div>
<span class="tip-class"> {{ $t('api_test.definition.recipient_tips') }} </span>
<span
class="tip-class" style="color: var(--primary_color);cursor: pointer;" @click="gotoApiMessage">
{{ $t('project_application.workstation.go_to_api_message') }}
</p>
<el-row v-if="apiSyncRuleRelation.sendNotice" style="margin-bottom: 5px; margin-top: 5px">
<el-col :span="4"
><span style="font-weight: bold; padding-left: 10px">{{ $t('api_test.definition.recipient') + ':' }}</span>
</el-col>
<el-col :span="20" style="color: var(--primary_color)">
<el-checkbox v-model="apiSyncRuleRelation.caseCreator">{{ 'CASE' + $t('api_test.creator') }}</el-checkbox>
</span>
<el-row v-if="apiSyncRuleRelation.sendNotice">
<div style="border-top: solid rgba(31, 35, 41, 0.15) 1px; margin: 16px 0;"></div>
<span class="text-class">{{ $t('api_test.definition.recipient') }}</span>
<div style="color: var(--primary_color);margin-top: 8px;">
<el-checkbox v-model="apiSyncRuleRelation.caseCreator"><span
class="text-class">{{ 'CASE' + $t('api_test.creator') }}</span></el-checkbox>
<el-checkbox v-model="apiSyncRuleRelation.scenarioCreator">
{{ $t('commons.scenario') + $t('api_test.creator') }}
<span class="text-class">{{ $t('commons.scenario') + $t('api_test.creator') }}</span>
</el-checkbox>
</el-col>
</div>
</el-row>
</el-row>
<el-row>
<el-checkbox v-model="apiSyncRuleRelation.showUpdateRule" style="padding-left: 10px"
>{{ $t('project_application.workstation.no_show_setting') }}
<span slot="footer" class="dialog-footer">
<div class="bottom-class">
<div class="close-class">
<el-checkbox v-model="apiSyncRuleRelation.showUpdateRule" style="color: #8F959E;width: 16px;height: 16px">
</el-checkbox>
<span class="text-class" style="margin-left: 8px;margin-right: 5px;">
{{ $t('project_application.workstation.no_show_setting') }}
</span>
<el-tooltip
class="ms-num"
effect="dark"
:content="$t('project_application.workstation.no_show_setting_tip')"
placement="top">
<i class="el-icon-warning"/>
<svg-icon iconClass="question" class-name="ms-menu-img"
:style="{color:'#8F959E',margin: '2px 0 0 0'}"></svg-icon>
</el-tooltip>
</el-row>
<span slot="footer" class="dialog-footer">
</div>
<div>
<el-button @click="batchSyncApiVisible = false">{{ $t('commons.cancel') }}</el-button>
<el-button type="primary" @click="batchSync()">{{ $t('commons.confirm') }}</el-button>
</div>
</div>
</span>
</el-dialog>
</template>
@ -140,5 +138,75 @@ export default {
</script>
<style scoped>
.box-class {
background: #FFFFFF;
border: 1px solid #DEE0E3;
border-radius: 4px;
width: 552px;
left: 4px;
top: -16px;
padding: 16px;
}
:deep(.el-dialog__title) {
font-size: 16px;
font-weight: 500;
/* left: 4px; */
margin-left: 4px;
color: #1F2329;
font-style: normal;
line-height: 24px;
}
.time-class {
font-style: normal;
font-weight: 500;
font-size: 14px;
line-height: 22px;
color: #1F2329;
margin-bottom: 8px;
display: flex;
justify-content: space-between;
align-items: center;
}
.tip-class {
font-style: normal;
font-weight: 400;
font-size: 14px;
line-height: 22px;
color: #646A73;
}
.bottom-class {
display: flex;
justify-content: space-between;
align-items: center;
margin: -40px 4px 4px;
}
.text-class {
font-style: normal;
font-weight: 400;
font-size: 14px;
line-height: 22px;
color: #1F2329;
}
.close-class {
display: flex;
align-items: center;
}
</style>
<style lang="scss" scoped>
.ms-menu-img {
width: 15px;
height: 15px;
border: 0;
display: inline-block;
box-sizing: border-box;
background-repeat: no-repeat;
background-position: 50% center;
}
</style>

View File

@ -1,7 +1,7 @@
<template>
<ms-edit-dialog
:visible.sync="visible"
width="300px"
width="400px"
:title="$t('commons.delete_all_version')"
:with-footer="false"
:close-on-click-modal="false"
@ -12,13 +12,9 @@
<el-select v-model="versionId" size="small" :placeholder="$t('project.version.please_input_version')">
<el-option v-for="v in versionData" :key="v.id" :label="v.name" :value="v.id" />
</el-select>
<el-popover
placement="top-start"
width="200"
trigger="hover"
:content="$t('api_definition.copy_data_from_other_version_tips')">
<i class="el-icon-warning" slot="reference" style="color: #f56c6c; margin: 0 0 0 5px" />
</el-popover>
</el-row>
<el-row style="margin: 0">
<p style="color: #939496">{{ $t('api_definition.copy_data_from_other_version_tips') }}</p>
</el-row>
<el-row style="margin-top: 10px">
<el-checkbox v-model="selectCase" v-permission="['PROJECT_API_DEFINITION:READ+CREATE_CASE']">{{

View File

@ -1,25 +1,28 @@
<template>
<div>
<el-row>
<el-col :span="4">{{ $t('api_test.mock.req_param') + ':' }}</el-col>
<el-col :span="20" style="color: var(--primary_color)">
<el-checkbox v-model="fromData.headers" @change="changeEvent">{{ 'Header' + '\xa0\xa0' }}</el-checkbox>
<el-checkbox v-model="fromData.query" @change="changeEvent"
>{{ $t('api_test.definition.request.query_param') }}
<span class="text-class">{{ $t('api_test.mock.req_param') }}</span>
<div style="color: var(--primary_color);margin-top: 8px;">
<el-checkbox v-model="fromData.headers" @change="changeEvent"><span class="text-class">{{
'Header' + '\xa0\xa0'
}}</span></el-checkbox>
<el-checkbox v-model="fromData.query" @change="changeEvent">
<span class="text-class">{{ $t('api_test.definition.request.query_param') }}</span>
</el-checkbox>
<el-checkbox v-model="fromData.rest" @change="changeEvent"
>{{ $t('api_test.definition.request.rest_param') }}
<el-checkbox v-model="fromData.rest" @change="changeEvent">
<span class="text-class">{{ $t('api_test.definition.request.rest_param') }}</span>
</el-checkbox>
<el-checkbox v-model="fromData.body" @change="changeEvent">{{ $t('api_test.request.body') }}</el-checkbox>
</el-col>
<el-checkbox v-model="fromData.body" @change="changeEvent"><span
class="text-class">{{ $t('api_test.request.body') }}</span></el-checkbox>
</div>
</el-row>
<el-row>
<el-col :span="4">{{ $t('api_test.definition.request.other_config') + ':' }}</el-col>
<el-col :span="20" style="color: var(--primary_color)">
<el-checkbox v-model="fromData.delNotSame" @change="changeEvent"
>{{ $t('workstation.delNotSame') }}
<el-row style="margin-top: 16px">
<span class="text-class">{{ $t('api_test.definition.request.other_config') }}</span>
<div style="color: var(--primary_color);margin-top: 8px;">
<el-checkbox v-model="fromData.delNotSame" @change="changeEvent">
<span class="text-class">{{ $t('workstation.delNotSame') }}</span>
</el-checkbox>
</el-col>
</div>
</el-row>
</div>
</template>
@ -57,7 +60,11 @@ export default {
</script>
<style scoped>
.el-row {
margin-bottom: 3px;
.text-class {
font-style: normal;
font-weight: 400;
font-size: 14px;
line-height: 22px;
color: #1F2329;
}
</style>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 44 44;" xml:space="preserve">
<g>
<path class="st0" d="M4.222 4.222A10.969 10.969 0 0 1 12 1c3.037 0 5.789 1.232 7.778 3.222l-.707.707.707-.707A10.969 10.969 0 0 1 23 12c0 3.037-1.232 5.789-3.222 7.778A10.969 10.969 0 0 1 12 23a10.969 10.969 0 0 1-7.778-3.222l.707-.707-.707.707A10.969 10.969
0 0 1 1 12c0-3.037 1.232-5.789 3.222-7.778ZM12 3a8.969 8.969 0 0 0-6.364 2.636A8.969
8.969 0 0 0 3 12a8.969 8.969 0 0 0 2.636 6.364A8.969 8.969 0 0 0 12 21a8.968 8.968 0 0 0 6.364-2.636A8.968 8.968 0 0 0 21 12a8.969 8.969 0 0 0-2.636-6.364A8.969 8.969 0 0 0 12 3Z"/>
<path class="st0"
d="M8 9.312a4 4 0 1 1 5 3.874v1.126a1 1 0 1 1-2 0v-2a1 1 0 0 1 1-1 2 2 0 1 0-2-2 1 1 0 0 1-2 0ZM12 18.812a1.25 1.25 0 1 0 0-2.5 1.25 1.25 0 0 0 0 2.5Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1005 B

View File

@ -147,7 +147,7 @@ export default {
},
getUiIndex() {
if (hasLicense()) {
return "ui";
return "/ui";
}
return "";
},

View File

@ -542,6 +542,9 @@ const message = {
performance: 'Performance',
scenario_case: 'Scenario Case'
},
sync_case_tips: 'Note: After ignoring, the affected use cases will no longer have reminders, please operate with caution',
batch_sync_api_tips: 'Batch synchronization, some use case parameters that do not need to be synchronized may also be overwritten, causing the test to fail, please operate with caution',
batch_ignore_case_tips: 'Note: After batch ignoring, the affected use cases will no longer have reminders, please operate with caution',
},
display: {
title: 'Theme',
@ -1334,7 +1337,7 @@ const message = {
one_click_sync: "One-click sync",
change_notification: "Change Notification",
recipient: "Recipient",
recipient_tips: "When the API changes, the associated CASE creator and automation scene creator will receive in-site messages",
recipient_tips: "When the API changes, the associated CASE creator and automation scene creator will receive in-site messages,can go to",
select_comp: {
no_data: "No Data",
add_data: "Add Data"

View File

@ -545,9 +545,9 @@ const message = {
performance: '性能测试',
scenario_case: '场景用例'
},
apply_tip:'未开启工作台待更新设置',
apply_tip: '未开启工作台待更新设置',
sync_case_tips: '注意: 忽略后,受影响的用例将不再有提醒,请谨慎操作',
batch_sync_api_tips: '注意: 批量同步,有可能部分不需要同步的用例参数也被覆盖,导致测试不通过,请谨慎操作',
batch_sync_api_tips: '批量同步,有可能部分不需要同步的用例参数也被覆盖,导致测试不通过,请谨慎操作',
batch_ignore_case_tips: '注意: 批量忽略后,受影响的用例将不再有提醒,请谨慎操作',
},
display: {
@ -1345,7 +1345,7 @@ const message = {
one_click_sync: "一键同步",
change_notification: "变更通知",
recipient: "接收人",
recipient_tips: "当API发生变化时关联的CASE创建人、自动化场景创建人会收到站内消息",
recipient_tips: "当API发生变化时关联的CASE创建人、自动化场景创建人会收到站内消息,可前往",
select_comp: {
no_data: "无数据",
add_data: "去添加"

View File

@ -544,7 +544,10 @@ const message = {
api_case: '接口用例',
performance: '性能測試',
scenario_case: '場景用例'
}
},
sync_case_tips: '注意: 忽略後,受影響的用例將不再有提醒,請謹慎操作',
batch_sync_api_tips: '批量同步,有可能部分不需要同步的用例參數也被覆蓋,導致測試不通過,請謹慎操作',
batch_ignore_case_tips: '注意: 批量忽略後,受影響的用例將不再有提醒,請謹慎操作',
},
display: {
title: '顯示設置',
@ -1341,7 +1344,7 @@ const message = {
one_click_sync: "一鍵同步",
change_notification: "變更通知",
recipient: "接收人",
recipient_tips: "當API發生變化時關聯的CASE創建人、自動化場景創建人會收到站內消息",
recipient_tips: "當API發生變化時關聯的CASE創建人、自動化場景創建人會收到站內消息,可前往",
select_comp: {
no_data: "無數據",
add_data: "去添加"