Merge remote-tracking branch 'origin/master'

This commit is contained in:
song.tianyang 2021-03-24 19:05:17 +08:00
commit 27e405fde5
20 changed files with 209 additions and 147 deletions

View File

@ -14,9 +14,9 @@ import java.util.List;
public class SwaggerApiExportResult extends ApiExportResult{ public class SwaggerApiExportResult extends ApiExportResult{
private String openapi; private String openapi;
private SwaggerInfo info; private SwaggerInfo info;
private String externalDocs; private JSONObject externalDocs;
private List<String> servers; private List<String> servers;
private List<SwaggerTag> tags; private List<SwaggerTag> tags;
private JSONObject paths; // Map<String, Object>, Object 里放 Operation 对象 private JSONObject paths; // Map<String, Object>, Object 里放 Operation 对象
private List<String> components; private JSONObject components;
} }

View File

@ -231,6 +231,9 @@ public class Swagger3Parser extends SwaggerAbstractParser {
MediaType mediaType = content.get(contentType); MediaType mediaType = content.get(contentType);
if (mediaType == null) { if (mediaType == null) {
Set<String> contentTypes = content.keySet(); Set<String> contentTypes = content.keySet();
if(contentTypes.size() == 0) { // 防止空指针
return;
}
contentType = contentTypes.iterator().next(); contentType = contentTypes.iterator().next();
if (StringUtils.isBlank(contentType)) { if (StringUtils.isBlank(contentType)) {
return; return;
@ -410,26 +413,34 @@ public class Swagger3Parser extends SwaggerAbstractParser {
result.setInfo(new SwaggerInfo()); result.setInfo(new SwaggerInfo());
result.setServers(new ArrayList<>()); result.setServers(new ArrayList<>());
result.setTags(new ArrayList<>()); result.setTags(new ArrayList<>());
result.setComponents(new ArrayList<>()); result.setComponents(new JSONObject());
result.setExternalDocs(new JSONObject());
JSONObject paths = new JSONObject(); JSONObject paths = new JSONObject();
JSONObject swaggerPath = new JSONObject();
for(ApiDefinitionWithBLOBs apiDefinition : apiDefinitionList) { for(ApiDefinitionWithBLOBs apiDefinition : apiDefinitionList) {
SwaggerApiInfo swaggerApiInfo = new SwaggerApiInfo(); // {tags:, summary:, description:, parameters:} SwaggerApiInfo swaggerApiInfo = new SwaggerApiInfo(); // {tags:, summary:, description:, parameters:}
swaggerApiInfo.setSummary(apiDefinition.getName()); swaggerApiInfo.setSummary(apiDefinition.getName());
// 设置导入后的模块名 根据 api moduleID 查库获得所属模块作为导出的模块名 // 设置导入后的模块名 根据 api moduleID 查库获得所属模块作为导出的模块名
ApiModuleService apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class); ApiModuleService apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class);
String moduleName = apiModuleService.getNode(apiDefinition.getModuleId()).getName(); String moduleName = "";
if(apiDefinition.getModuleId() != null) { // module_id 可能为空
moduleName = apiModuleService.getNode(apiDefinition.getModuleId()).getName();
}
swaggerApiInfo.setTags(Arrays.asList(moduleName)); swaggerApiInfo.setTags(Arrays.asList(moduleName));
// 设置请求体 // 设置请求体
JSONObject requestObject = JSON.parseObject(apiDefinition.getRequest()); // 将api的request属性转换成JSON对象以便获得参数 JSONObject requestObject = JSON.parseObject(apiDefinition.getRequest()); // 将api的request属性转换成JSON对象以便获得参数
JSONObject requestBody = buildRequestBody(requestObject); JSONObject requestBody = buildRequestBody(requestObject);
swaggerApiInfo.setRequestBody(requestBody); swaggerApiInfo.setRequestBody(requestBody);
// 设置响应体
swaggerApiInfo.setResponses(new JSONObject());
// 设置请求参数列表 // 设置请求参数列表
List<JSONObject> paramsList = buildParameters(requestObject); List<JSONObject> paramsList = buildParameters(requestObject);
swaggerApiInfo.setParameters(paramsList); swaggerApiInfo.setParameters(paramsList);
swaggerPath.put(apiDefinition.getMethod().toLowerCase(), JSON.parseObject(JSON.toJSONString(swaggerApiInfo))); // 设置api的请求类型和api定义参数 JSONObject methodDetail = JSON.parseObject(JSON.toJSONString(swaggerApiInfo));
paths.put(apiDefinition.getPath(), swaggerPath); if(paths.getJSONObject(apiDefinition.getPath()) == null) {
paths.put(apiDefinition.getPath(), new JSONObject());
} // 一个路径下有多个发方法如postget因此是一个 JSONObject 类型
paths.getJSONObject(apiDefinition.getPath()).put(apiDefinition.getMethod().toLowerCase(), methodDetail);
} }
result.setPaths(paths); result.setPaths(paths);
return result; return result;
@ -477,7 +488,9 @@ public class Swagger3Parser extends SwaggerAbstractParser {
schema.put("format", null); schema.put("format", null);
typeName.put("schema", schema); typeName.put("schema", schema);
JSONObject content = new JSONObject(); JSONObject content = new JSONObject();
content.put(typeMap.get(type), typeName); if (type != null && StringUtils.isNotBlank(type)) {
content.put(typeMap.get(type), typeName);
}
requestBody.put("content", content); requestBody.put("content", content);
return requestBody; return requestBody;
} }

View File

@ -14,4 +14,5 @@ public class SwaggerApiInfo {
private String summary; // 对应 API 的名字 private String summary; // 对应 API 的名字
private List<JSONObject> parameters; // 对应 API 的请求参数 private List<JSONObject> parameters; // 对应 API 的请求参数
private JSONObject requestBody; private JSONObject requestBody;
private JSONObject responses;
} }

View File

@ -267,6 +267,9 @@
open(api) { open(api) {
if (api) { if (api) {
let data = JSON.parse(JSON.stringify(api)); let data = JSON.parse(JSON.stringify(api));
if (data.protocol === "dubbo://") {
data.protocol = "DUBBO";
}
data.id = getUUID(); data.id = getUUID();
this.httpForm = {id: data.id, name: data.name, protocol: data.protocol, path: data.path, method: api.method, userId: getCurrentUser().id, request: data}; this.httpForm = {id: data.id, name: data.name, protocol: data.protocol, path: data.path, method: api.method, userId: getCurrentUser().id, request: data};
this.getMaintainerOptions(); this.getMaintainerOptions();

View File

@ -162,6 +162,7 @@
.script-content { .script-content {
height: calc(100vh - 570px); height: calc(100vh - 570px);
min-height: 250px;
} }
.script-index { .script-index {

View File

@ -80,7 +80,7 @@
</span> </span>
</el-tooltip> </el-tooltip>
<el-row> <el-row>
<el-link class="ms-variable-link" @click="batchAdd" style="color: #783887"> {{ $t("commons.batch_add") }} <el-link class="ms-variable-link" @click="batchAdd" style="color: #783887" :disabled="disabled"> {{ $t("commons.batch_add") }}
</el-link> </el-link>
</el-row> </el-row>
<div style="min-height: 400px"> <div style="min-height: 400px">

View File

@ -4,7 +4,7 @@
{{ description }} {{ description }}
</span> </span>
<el-row> <el-row>
<el-checkbox v-model="isSelectAll" v-if="items.length > 1"/> <el-checkbox v-model="isSelectAll" v-if="isShowEnable === true && items.length > 1"/>
</el-row> </el-row>
<div class="kv-row item" v-for="(item, index) in items" :key="index"> <div class="kv-row item" v-for="(item, index) in items" :key="index">
<el-row type="flex" :gutter="20" justify="space-between" align="middle"> <el-row type="flex" :gutter="20" justify="space-between" align="middle">
@ -52,7 +52,6 @@
valuePlaceholder: String, valuePlaceholder: String,
isShowEnable: { isShowEnable: {
type: Boolean, type: Boolean,
default: true
}, },
description: String, description: String,
items: Array, items: Array,

View File

@ -155,6 +155,11 @@
created() { created() {
this.getEnvironments(); this.getEnvironments();
}, },
computed: {
projectId() {
return this.$store.state.projectId
},
},
methods: { methods: {
addPre() { addPre() {
let jsr223PreProcessor = createComponent("JSR223PreProcessor"); let jsr223PreProcessor = createComponent("JSR223PreProcessor");
@ -210,7 +215,8 @@
getEnvironments() { getEnvironments() {
this.environments = []; this.environments = [];
this.$get('/api/environment/list/' + getCurrentProjectID(), response => { let id = this.request.projectId ? this.request.projectId : this.projectId;
this.$get('/api/environment/list/' + id, response => {
this.environments = response.data; this.environments = response.data;
this.environments.forEach(environment => { this.environments.forEach(environment => {
parseEnvironment(environment); parseEnvironment(environment);

View File

@ -1,7 +1,7 @@
<template> <template>
<el-form :model="request" :rules="rules" ref="request" label-width="100px" size="small" v-loading="loading" <el-form :model="request" :rules="rules" ref="request" label-width="100px" size="small" v-loading="loading"
:disabled="isReadOnly"> :disabled="isReadOnly">
<el-button class="get-provider" type="primary" size="small" @click="getProviderList">Get Provider List</el-button> <el-button class="get-provider" type="primary" size="mini" @click="getProviderList">Get Provider List</el-button>
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="Interfaces" prop="interfaces"> <el-form-item label="Interfaces" prop="interfaces">

View File

@ -8,20 +8,10 @@
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('api_test.definition.request.response_header')" name="headers" class="pane"> <el-tab-pane :label="$t('api_test.definition.request.response_header')" name="headers" class="pane">
<!--<div style="width: 400px">-->
<!--<pre>{{ response.responseResult.headers }}</pre>-->
<!--</div>-->
<ms-code-edit :mode="'text'" :read-only="true" :data.sync="response.responseResult.headers"/> <ms-code-edit :mode="'text'" :read-only="true" :data.sync="response.responseResult.headers"/>
</el-tab-pane> </el-tab-pane>
<!--<el-tab-pane label="Cookie" name="cookie" class="pane cookie">-->
<!--<pre>{{response.cookies}}</pre>-->
<!--</el-tab-pane>-->
<el-tab-pane :label="$t('api_test.definition.request.console')" name="console" class="pane"> <el-tab-pane :label="$t('api_test.definition.request.console')" name="console" class="pane">
<!--<div style="width: 400px">-->
<!--<pre>{{response.responseResult.console}}</pre>-->
<!--</div>-->
<ms-code-edit :mode="'text'" :read-only="true" :data.sync="response.responseResult.console"/> <ms-code-edit :mode="'text'" :read-only="true" :data.sync="response.responseResult.console"/>
</el-tab-pane> </el-tab-pane>
@ -30,29 +20,10 @@
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('api_test.request.extract.label')" name="label" class="pane"> <el-tab-pane :label="$t('api_test.request.extract.label')" name="label" class="pane">
<!--<div style="width: 400px">-->
<!--<pre>{{response.responseResult.vars}}</pre>-->
<!--</div>-->
<ms-code-edit :mode="'text'" :read-only="true" :data.sync="response.responseResult.vars"/> <ms-code-edit :mode="'text'" :read-only="true" :data.sync="response.responseResult.vars"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('api_report.request_body')" name="request_body" class="pane"> <el-tab-pane :label="$t('api_report.request_body')" name="request_body" class="pane">
<!--<div class="ms-div">-->
<!--{{$t('api_test.request.address')}} :-->
<!--<pre>{{ response.url }}</pre>-->
<!--</div>-->
<!--<div class="ms-div">-->
<!--{{$t('api_test.scenario.headers')}} :-->
<!--<pre>{{ response.headers }}</pre>-->
<!--</div>-->
<!--<div class="ms-div">-->
<!--Cookies :-->
<!--<pre>{{response.cookies}}</pre>-->
<!--</div>-->
<!--<div class="ms-div">-->
<!--Body :-->
<!--<pre>{{response.body ? response.body:""}}</pre>-->
<!--</div>-->
<ms-code-edit :mode="'text'" :read-only="true" :data.sync="reqMessages"/> <ms-code-edit :mode="'text'" :read-only="true" :data.sync="reqMessages"/>
</el-tab-pane> </el-tab-pane>

View File

@ -190,8 +190,8 @@ export default {
let req = this.api.request; let req = this.api.request;
req.id = getUUID(); req.id = getUUID();
data.request = JSON.stringify(req); data.request = JSON.stringify(req);
data.method = this.api.method; data.method = req.method;
data.path = this.api.path; data.path = req.path;
data.url = this.api.url; data.url = this.api.url;
data.status = this.api.status; data.status = this.api.status;
data.userId = this.api.userId; data.userId = this.api.userId;

View File

@ -9,9 +9,9 @@
<el-popover <el-popover
placement="right-end" placement="right-end"
title="示例" title="示例"
width="400" width="600"
trigger="click" trigger="click">
:content="title"> <ms-code-edit :read-only="true" height="400px" :data.sync="title" :modes="modes" :mode="'html'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference"> <el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.mail_template_example') }} {{ $t('organization.message.mail_template_example') }}
</el-button> </el-button>
@ -22,6 +22,7 @@
width="400" width="400"
trigger="click" trigger="click"
:content="robotTitle"> :content="robotTitle">
<ms-code-edit :read-only="true" height="200px" :data.sync="robotTitle" :modes="modes" :mode="'text'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference"> <el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.robot_template') }} {{ $t('organization.message.robot_template') }}
</el-button> </el-button>
@ -132,6 +133,7 @@
<script> <script>
import {hasLicense} from "@/common/js/utils"; import {hasLicense} from "@/common/js/utils";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
const TASK_TYPE = 'DEFECT_TASK'; const TASK_TYPE = 'DEFECT_TASK';
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/); const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
@ -140,6 +142,7 @@ const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./
export default { export default {
name: "DefectTaskNotification", name: "DefectTaskNotification",
components: { components: {
MsCodeEdit,
"NoticeTemplate": noticeTemplate.default "NoticeTemplate": noticeTemplate.default
}, },
props: { props: {
@ -149,6 +152,7 @@ export default {
}, },
data() { data() {
return { return {
modes: ['text', 'html'],
title: "<!DOCTYPE html>\n" + title: "<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" + "<html lang=\"en\">\n" +
"<head>\n" + "<head>\n" +
@ -274,6 +278,7 @@ export default {
.el-row { .el-row {
margin-bottom: 10px; margin-bottom: 10px;
} }
.el-button { .el-button {
margin-left: 10px; margin-left: 10px;
} }

View File

@ -9,9 +9,9 @@
<el-popover <el-popover
placement="right-end" placement="right-end"
title="示例" title="示例"
width="400" width="600"
trigger="click" trigger="click">
:content="title"> <ms-code-edit :read-only="true" height="400px" :data.sync="title" :modes="modes" :mode="'html'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference"> <el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.mail_template_example') }} {{ $t('organization.message.mail_template_example') }}
</el-button> </el-button>
@ -19,9 +19,9 @@
<el-popover <el-popover
placement="right-end" placement="right-end"
title="示例" title="示例"
width="400" width="600"
trigger="click" trigger="click">
:content="robotTitle"> <ms-code-edit :read-only="true" height="200px" :data.sync="robotTitle" :modes="modes" :mode="'text'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference"> <el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.robot_template') }} {{ $t('organization.message.robot_template') }}
</el-button> </el-button>
@ -136,6 +136,7 @@
<script> <script>
import {hasLicense} from "@/common/js/utils"; import {hasLicense} from "@/common/js/utils";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
const TASK_TYPE = 'JENKINS_TASK'; const TASK_TYPE = 'JENKINS_TASK';
@ -145,6 +146,7 @@ const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./
export default { export default {
name: "JenkinsNotification", name: "JenkinsNotification",
components: { components: {
MsCodeEdit,
"NoticeTemplate": noticeTemplate.default "NoticeTemplate": noticeTemplate.default
}, },
props: { props: {
@ -154,6 +156,7 @@ export default {
}, },
data() { data() {
return { return {
modes: ['text', 'html'],
title: '<!DOCTYPE html>\n' + title: '<!DOCTYPE html>\n' +
'<html lang="en">\n' + '<html lang="en">\n' +
'<head>\n' + '<head>\n' +

View File

@ -9,9 +9,9 @@
<el-popover <el-popover
placement="right-end" placement="right-end"
title="示例" title="示例"
width="400" width="600"
trigger="click" trigger="click">
:content="title"> <ms-code-edit :read-only="true" height="400px" :data.sync="title" :modes="modes" :mode="'html'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference"> <el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.mail_template_example') }} {{ $t('organization.message.mail_template_example') }}
</el-button> </el-button>
@ -19,9 +19,9 @@
<el-popover <el-popover
placement="right-end" placement="right-end"
title="示例" title="示例"
width="400" width="200"
trigger="click" trigger="click" >
:content="robotTitle"> <ms-code-edit :read-only="true" height="200px" :data.sync="robotTitle" :modes="modes" :mode="'text'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference"> <el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.robot_template') }} {{ $t('organization.message.robot_template') }}
</el-button> </el-button>
@ -136,6 +136,7 @@
<script> <script>
import {hasLicense} from "@/common/js/utils"; import {hasLicense} from "@/common/js/utils";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/); const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./notice/NoticeTemplate.vue") : {}; const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./notice/NoticeTemplate.vue") : {};
@ -143,6 +144,7 @@ const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./
export default { export default {
name: "ScheduleTaskNotification", name: "ScheduleTaskNotification",
components: { components: {
MsCodeEdit,
"NoticeTemplate": noticeTemplate.default "NoticeTemplate": noticeTemplate.default
}, },
props: { props: {
@ -155,6 +157,7 @@ export default {
}, },
data() { data() {
return { return {
modes: ['text', 'html'],
title: '<!DOCTYPE html>\n' + title: '<!DOCTYPE html>\n' +
'<html lang="en">\n' + '<html lang="en">\n' +
'<head>\n' + '<head>\n' +

View File

@ -9,9 +9,9 @@
<el-popover <el-popover
placement="right-end" placement="right-end"
title="示例" title="示例"
width="400" width="600"
trigger="click" trigger="click">
:content="title"> <ms-code-edit :read-only="true" height="400px" :data.sync="title" :modes="modes" :mode="'html'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference"> <el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.mail_template_example') }} {{ $t('organization.message.mail_template_example') }}
</el-button> </el-button>
@ -19,9 +19,9 @@
<el-popover <el-popover
placement="right-end" placement="right-end"
title="示例" title="示例"
width="400" width="600"
trigger="click" trigger="click">
:content="robotTitle"> <ms-code-edit :read-only="true" height="200px" :data.sync="robotTitle" :modes="modes" :mode="'text'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference"> <el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.robot_template') }} {{ $t('organization.message.robot_template') }}
</el-button> </el-button>
@ -133,6 +133,7 @@
<script> <script>
import {hasLicense} from "@/common/js/utils"; import {hasLicense} from "@/common/js/utils";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
const TASK_TYPE = 'TEST_PLAN_TASK'; const TASK_TYPE = 'TEST_PLAN_TASK';
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/); const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
@ -141,6 +142,7 @@ const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./
export default { export default {
name: "TestPlanTaskNotification", name: "TestPlanTaskNotification",
components: { components: {
MsCodeEdit,
"NoticeTemplate": noticeTemplate.default "NoticeTemplate": noticeTemplate.default
}, },
props: { props: {
@ -150,6 +152,7 @@ export default {
}, },
data() { data() {
return { return {
modes: ['text', 'html'],
title: "<!DOCTYPE html>\n" + title: "<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" + "<html lang=\"en\">\n" +
"<head>\n" + "<head>\n" +
@ -308,6 +311,7 @@ export default {
.el-row { .el-row {
margin-bottom: 10px; margin-bottom: 10px;
} }
.el-button { .el-button {
margin-left: 10px; margin-left: 10px;
} }

View File

@ -9,9 +9,9 @@
<el-popover <el-popover
placement="right-end" placement="right-end"
title="示例" title="示例"
width="400" width="600"
trigger="click" trigger="click">
:content="title"> <ms-code-edit :read-only="true" height="400px" :data.sync="title" :modes="modes" :mode="'html'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference"> <el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.mail_template_example') }} {{ $t('organization.message.mail_template_example') }}
</el-button> </el-button>
@ -19,9 +19,9 @@
<el-popover <el-popover
placement="right-end" placement="right-end"
title="示例" title="示例"
width="400" width="600"
trigger="click" trigger="click">
:content="robotTitle"> <ms-code-edit :read-only="true" height="200px" :data.sync="robotTitle" :modes="modes" :mode="'text'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference"> <el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.robot_template') }} {{ $t('organization.message.robot_template') }}
</el-button> </el-button>
@ -133,6 +133,7 @@
<script> <script>
import {hasLicense} from "@/common/js/utils"; import {hasLicense} from "@/common/js/utils";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
const TASK_TYPE = 'REVIEW_TASK'; const TASK_TYPE = 'REVIEW_TASK';
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/); const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
@ -141,6 +142,7 @@ const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./
export default { export default {
name: "TestReviewNotification", name: "TestReviewNotification",
components: { components: {
MsCodeEdit,
"NoticeTemplate": noticeTemplate.default "NoticeTemplate": noticeTemplate.default
}, },
props: { props: {
@ -150,6 +152,7 @@ export default {
}, },
data() { data() {
return { return {
modes: ['text', 'html'],
title: "<!DOCTYPE html>\n" + title: "<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" + "<html lang=\"en\">\n" +
"<head>\n" + "<head>\n" +
@ -313,6 +316,7 @@ export default {
.el-row { .el-row {
margin-bottom: 10px; margin-bottom: 10px;
} }
.el-button { .el-button {
margin-left: 10px; margin-left: 10px;
} }

View File

@ -9,7 +9,7 @@
id="inputDelay" id="inputDelay"
type="primary" type="primary"
:content="$t('commons.save')" :content="$t('commons.save')"
size="small" @exec="saveCase" size="small" @click="saveCase"
icon="" icon=""
title="ctrl + s"/> title="ctrl + s"/>
<el-dropdown v-else split-button type="primary" class="ms-api-buttion" @click="handleCommand" <el-dropdown v-else split-button type="primary" class="ms-api-buttion" @click="handleCommand"
@ -62,14 +62,14 @@
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="7"> <!-- <el-col :span="7">-->
<el-form-item label="评审状态" :label-width="formLabelWidth" prop="reviewStatus"> <!-- <el-form-item label="评审状态" :label-width="formLabelWidth" prop="reviewStatus">-->
<el-select size="small" v-model="form.reviewStatus" class="ms-case-input"> <!-- <el-select size="small" v-model="form.reviewStatus" class="ms-case-input">-->
<el-option v-for="item in options" :key="item.id" :label="item.label" :value="item.id"> <!-- <el-option v-for="item in options" :key="item.id" :label="item.label" :value="item.id">-->
</el-option> <!-- </el-option>-->
</el-select> <!-- </el-select>-->
</el-form-item> <!-- </el-form-item>-->
</el-col> <!-- </el-col>-->
<el-col :span="7"> <el-col :span="7">
<el-form-item :label="$t('commons.tag')" :label-width="formLabelWidth" prop="tag"> <el-form-item :label="$t('commons.tag')" :label-width="formLabelWidth" prop="tag">
<ms-input-tag :currentScenario="form" v-if="showInputTag" ref="tag" class="ms-case-input"/> <ms-input-tag :currentScenario="form" v-if="showInputTag" ref="tag" class="ms-case-input"/>
@ -88,8 +88,6 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row>
<el-row>
<el-col :span="7"> <el-col :span="7">
<el-form-item :label="$t('test_track.case.priority')" :label-width="formLabelWidth" prop="priority"> <el-form-item :label="$t('test_track.case.priority')" :label-width="formLabelWidth" prop="priority">
<el-select :disabled="readOnly" v-model="form.priority" clearable <el-select :disabled="readOnly" v-model="form.priority" clearable
@ -101,16 +99,18 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="14"> </el-row>
<el-row>
<el-col :span="7">
<el-form-item :label="$t('test_track.case.relate_test')" :label-width="formLabelWidth"> <el-form-item :label="$t('test_track.case.relate_test')" :label-width="formLabelWidth">
<el-cascader filterable placeholder="请选择要关联的测试" show-all-levels v-model="form.selected" :props="props" <el-cascader :options="sysList" filterable placeholder="请选择要关联的测试" show-all-levels
class="ms-case"></el-cascader> v-model="form.selected" :props="props"
class="ms-case" @change="clearInput" ref="cascade"></el-cascader>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row>
<el-row> <el-col :span="7">
<el-col :span="10">
<el-form-item label="关联需求" :label-width="formLabelWidth" prop="demandId"> <el-form-item label="关联需求" :label-width="formLabelWidth" prop="demandId">
<el-select filterable :disabled="readOnly" v-model="form.demandId" @visible-change="visibleChange" <el-select filterable :disabled="readOnly" v-model="form.demandId" @visible-change="visibleChange"
placeholder="请选择要关联的需求" class="ms-case-input"> placeholder="请选择要关联的需求" class="ms-case-input">
@ -124,7 +124,7 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="10" :offset="1"> <el-col :span="7">
<el-form-item label="需求ID/名称" :label-width="formLabelWidth" prop="demandName" <el-form-item label="需求ID/名称" :label-width="formLabelWidth" prop="demandName"
v-if="form.demandId=='other'"> v-if="form.demandId=='other'">
<el-input v-model="form.demandName"></el-input> <el-input v-model="form.demandName"></el-input>
@ -290,7 +290,7 @@
<script> <script>
import {TokenKey, WORKSPACE_ID} from '@/common/js/constants'; import {TokenKey, WORKSPACE_ID} from '@/common/js/constants';
import MsDialogFooter from '../../../common/components/MsDialogFooter' import MsDialogFooter from '../../../common/components/MsDialogFooter'
import {getCurrentUser, listenGoBack, removeGoBackListener} from "@/common/js/utils"; import {getCurrentUser, handleCtrlSEvent, listenGoBack, removeGoBackListener} from "@/common/js/utils";
import {Message} from "element-ui"; import {Message} from "element-ui";
import TestCaseAttachment from "@/business/components/track/case/components/TestCaseAttachment"; import TestCaseAttachment from "@/business/components/track/case/components/TestCaseAttachment";
import {buildNodePath} from "../../../api/definition/model/NodeTree"; import {buildNodePath} from "../../../api/definition/model/NodeTree";
@ -315,43 +315,10 @@ export default {
return { return {
props: { props: {
multiple: true, multiple: true,
lazy: true, //lazy: true,
lazyLoad: ((node, resolve) => { //lazyLoad:this.lazyLoad
const {level} = node;
if (node.level == 0) {
const nodes = TEST
.map(item => ({
value: item.id,
label: item.name,
leaf: level >= 1
}));
resolve(nodes)
}
if (node.level == 1) {
this.testOptions = [];
let url = '';
this.form.type = node.data.value
if (this.form.type === 'testcase' || this.form.type === 'automation') {
url = '/api/' + this.form.type + '/list/' + this.projectId
} else if (this.form.type === 'performance' || this.form.type === 'api') {
url = '/' + this.form.type + '/list/' + this.projectId
}
if (this.projectId && this.form.type != '' && this.form.type != 'undefined') {
this.$get(url, response => {
const nodes = response.data
.map(item => ({
value: item.id,
label: item.name,
leaf: level >= 1
}));
resolve(nodes)
});
}
}
}),
}, },
sysList: [],//
options: REVIEW_STATUS, options: REVIEW_STATUS,
statuOptions: API_STATUS, statuOptions: API_STATUS,
comments: [], comments: [],
@ -395,6 +362,7 @@ export default {
{max: 255, message: this.$t('test_track.length_less_than') + '255', trigger: 'blur'} {max: 255, message: this.$t('test_track.length_less_than') + '255', trigger: 'blur'}
], ],
module: [{required: true, message: this.$t('test_track.case.input_module'), trigger: 'change'}], module: [{required: true, message: this.$t('test_track.case.input_module'), trigger: 'change'}],
demandName: [{required: true, message: this.$t('test_track.case.input_demand_name'), trigger: 'change'}],
maintainer: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}], maintainer: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
priority: [{required: true, message: this.$t('test_track.case.input_priority'), trigger: 'change'}], priority: [{required: true, message: this.$t('test_track.case.input_priority'), trigger: 'change'}],
method: [{required: true, message: this.$t('test_track.case.input_method'), trigger: 'change'}], method: [{required: true, message: this.$t('test_track.case.input_method'), trigger: 'change'}],
@ -462,8 +430,87 @@ export default {
this.$emit('setModuleOptions', this.moduleOptions); this.$emit('setModuleOptions', this.moduleOptions);
} }
}, },
created() {
this.loadOptions();
this.addListener(); // ctrl s
},
methods: { methods: {
clearInput() {
//this.$refs['cascade'].panel.clearCheckedNodes()
},
async loadOptions(sysLib) {
sysLib = TEST
.map(item => ({
value: item.id,
label: item.name,
}));
let array = [];
for (let i = 0; i < sysLib.length; i++) {
if (sysLib.length > 0) {
let res = await this.getTestOptions(sysLib[i].value);
sysLib[i].children = res;
}
array.push(sysLib[i]);
}
this.sysList = array;
},
getTestOptions(val) {
this.form.type = val
this.testOptions = [];
let url = '';
if (this.form.type === 'testcase' || this.form.type === 'automation') {
url = '/api/' + this.form.type + '/list/' + this.projectId
} else if (this.form.type === 'performance' || this.form.type === 'api') {
url = '/' + this.form.type + '/list/' + this.projectId
}
return new Promise((resolve, reject) => {
this.$get(url).then(res => {
console.log(res.data.data)
const data = res.data.data.map(item => ({
value: item.id,
label: item.name,
leaf: true
}))
resolve(data)
}).catch((err) => {
reject(err)
})
})
},
/* lazyLoad(node, resolve){
const { level } = node;
if(node.level==0){
const nodes = TEST
.map(item => ({
value: item.id,
label: item.name,
leaf: level >= 1
}));
resolve(nodes)
}
if(node.level==1){
this.projectId = getCurrentProjectID()
this.testOptions = [];
let url = '';
this.form.type=node.data.value
if (this.form.type === 'testcase' || this.form.type === 'automation') {
url = '/api/' + this.form.type + '/list/' + this.projectId
} else if (this.form.type === 'performance' || this.form.type === 'api') {
url = '/' + this.form.type + '/list/' + this.projectId
}
if (this.projectId && this.form.type != '' && this.form.type != 'undefined') {
this.$get(url, response => {
const nodes = response.data
.map(item => ({
value: item.id,
label: item.name,
leaf: level >= 1
}));
resolve(nodes)
});
}
}
},*/
handleCommand(e) { handleCommand(e) {
if (e === "ADD_AND_CREATE") { if (e === "ADD_AND_CREATE") {
this.$refs['caseFrom'].validate((valid) => { this.$refs['caseFrom'].validate((valid) => {
@ -506,6 +553,9 @@ export default {
this.$nextTick(() => (this.isStepTableAlive = true)); this.$nextTick(() => (this.isStepTableAlive = true));
}, },
open(testCase) { open(testCase) {
/*
this.form.selected=[["automation", "3edaaf31-3fa4-4a53-9654-320205c2953a"],["automation", "3aa58bd1-c986-448c-8060-d32713dbd4eb"]]
*/
if (window.history && window.history.pushState) { if (window.history && window.history.pushState) {
history.pushState(null, null, document.URL); history.pushState(null, null, document.URL);
window.addEventListener('popstate', this.close); window.addEventListener('popstate', this.close);
@ -577,7 +627,7 @@ export default {
}) })
}) })
}, },
setFormData(testCase) { async setFormData(testCase) {
testCase.tags = JSON.parse(testCase.tags); testCase.tags = JSON.parse(testCase.tags);
testCase.selected = JSON.parse(testCase.testId); testCase.selected = JSON.parse(testCase.testId);
let tmp = {}; let tmp = {};
@ -587,11 +637,12 @@ export default {
tmp.steps = [] tmp.steps = []
} }
Object.assign(this.form, tmp); Object.assign(this.form, tmp);
console.log(this.form.selected)
this.form.module = testCase.nodeId; this.form.module = testCase.nodeId;
/*
this.form.testId=testCase.selected
*/
this.getFileMetaData(testCase); this.getFileMetaData(testCase);
/* testCase.selected = JSON.parse(testCase.testId);
this.form.selected= testCase.selected*/
await this.loadOptions(this.sysList)
}, },
setTestCaseExtInfo(testCase) { setTestCaseExtInfo(testCase) {
this.testCase = {}; this.testCase = {};
@ -710,7 +761,7 @@ export default {
if (this.form.tags instanceof Array) { if (this.form.tags instanceof Array) {
this.form.tags = JSON.stringify(this.form.tags); this.form.tags = JSON.stringify(this.form.tags);
} }
param.testId = JSON.stringify(this.form.selected) param.testId=JSON.stringify(this.form.selected)
param.tags = this.form.tags; param.tags = this.form.tags;
param.type = 'functional' param.type = 'functional'
return param; return param;
@ -782,21 +833,7 @@ export default {
this.maintainerOptions = response.data; this.maintainerOptions = response.data;
}); });
}, },
getTestOptions(val) {
this.testOptions = [];
let url = '';
if (this.form.type === 'testcase' || this.form.type === 'automation') {
url = '/api/' + this.form.type + '/list/' + this.projectId
} else if (this.form.type === 'performance' || this.form.type === 'api') {
url = '/' + this.form.type + '/list/' + this.projectId
}
if (this.projectId && this.form.type != '' && this.form.type != 'undefined') {
this.result = this.$get(url, response => {
this.testOptions = response.data;
this.testOptions.unshift({id: 'other', name: this.$t('test_track.case.other')})
});
}
},
visibleChange(flag) { visibleChange(flag) {
if (flag) { if (flag) {
this.getDemandOptions(); this.getDemandOptions();
@ -936,6 +973,15 @@ export default {
/// todo: /// todo:
return file.size > 0; return file.size > 0;
}, },
addListener() {
document.addEventListener("keydown", this.createCtrlSHandle);
},
removeListener() {
document.removeEventListener("keydown", this.createCtrlSHandle);
},
createCtrlSHandle(event) {
handleCtrlSEvent(event, this.saveCase);
},
} }
} }
</script> </script>

View File

@ -1166,6 +1166,7 @@ export default {
input_type: "Please select type", input_type: "Please select type",
input_method: "Please select method", input_method: "Please select method",
input_prerequisite: "Please select prerequisite", input_prerequisite: "Please select prerequisite",
input_demand_name: "Please input demand id or name",
delete_confirm: "Confirm delete test case", delete_confirm: "Confirm delete test case",
delete: "Delete case", delete: "Delete case",
save_create_continue: "Save and create continue", save_create_continue: "Save and create continue",

View File

@ -1170,6 +1170,7 @@ export default {
input_type: "请选择用例类型", input_type: "请选择用例类型",
input_method: "请选择测试方式", input_method: "请选择测试方式",
input_prerequisite: "请输入前置条件", input_prerequisite: "请输入前置条件",
input_demand_name: "请输入需求ID或名称",
delete_confirm: "确认删除测试用例", delete_confirm: "确认删除测试用例",
delete: "删除用例", delete: "删除用例",
save_create_continue: "保存并继续创建", save_create_continue: "保存并继续创建",

View File

@ -1168,6 +1168,7 @@ export default {
input_type: "請選擇用例類型", input_type: "請選擇用例類型",
input_method: "請選擇測試方式", input_method: "請選擇測試方式",
input_prerequisite: "請輸入前置條件", input_prerequisite: "請輸入前置條件",
input_demand_name: "請輸入請求ID或名稱",
delete_confirm: "確認刪除測試用例", delete_confirm: "確認刪除測試用例",
delete: "刪除用例", delete: "刪除用例",
save_create_continue: "保存並繼續創建", save_create_continue: "保存並繼續創建",