This commit is contained in:
wenyann 2020-08-19 10:02:22 +08:00
commit 29f5e772a1
20 changed files with 378 additions and 87 deletions

3
backend/.gitignore vendored
View File

@ -31,4 +31,5 @@ target
.settings .settings
.project .project
.classpath .classpath
.factorypath .factorypath
*.jar

View File

@ -369,6 +369,16 @@
<version>2.6</version> <version>2.6</version>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/jmeter/lib/**/*.jar</exclude>
</excludes>
</configuration>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId> <artifactId>maven-antrun-plugin</artifactId>
@ -396,6 +406,35 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<phase>generate-resources</phase>
<goals>
<goal>copy</goal>
</goals>
</execution>
</executions>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_functions</artifactId>
<version>${jmeter.version}</version>
<type>jar</type>
<overWrite>true</overWrite>
<outputDirectory>src/main/resources/jmeter/lib/ext</outputDirectory>
<destFileName>ApacheJMeter_functions.jar</destFileName>
</artifactItem>
</artifactItems>
<outputDirectory>${project.build.directory}/wars</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>true</overWriteSnapshots>
</configuration>
</plugin>
<plugin> <plugin>
<groupId>org.mybatis.generator</groupId> <groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId> <artifactId>mybatis-generator-maven-plugin</artifactId>

View File

@ -6,6 +6,8 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import io.metersphere.api.dto.scenario.KeyValue; import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.api.dto.scenario.assertions.Assertions; import io.metersphere.api.dto.scenario.assertions.Assertions;
import io.metersphere.api.dto.scenario.extract.Extract; import io.metersphere.api.dto.scenario.extract.Extract;
import io.metersphere.api.dto.scenario.processor.BeanShellPostProcessor;
import io.metersphere.api.dto.scenario.processor.BeanShellPreProcessor;
import io.metersphere.api.dto.scenario.request.dubbo.ConfigCenter; import io.metersphere.api.dto.scenario.request.dubbo.ConfigCenter;
import io.metersphere.api.dto.scenario.request.dubbo.ConsumerAndService; import io.metersphere.api.dto.scenario.request.dubbo.ConsumerAndService;
import io.metersphere.api.dto.scenario.request.dubbo.RegistryCenter; import io.metersphere.api.dto.scenario.request.dubbo.RegistryCenter;
@ -43,4 +45,8 @@ public class DubboRequest implements Request {
private Assertions assertions; private Assertions assertions;
@JSONField(ordinal = 11) @JSONField(ordinal = 11)
private Extract extract; private Extract extract;
@JSONField(ordinal = 12)
private BeanShellPreProcessor beanShellPreProcessor;
@JSONField(ordinal = 13)
private BeanShellPostProcessor beanShellPostProcessor;
} }

View File

@ -118,7 +118,6 @@ test_case_already_exists_excel=There are duplicate test cases in the import file
test_case_module_already_exists=The module name already exists at the same level test_case_module_already_exists=The module name already exists at the same level
api_test_name_already_exists=Test name already exists api_test_name_already_exists=Test name already exists
functional_method_tip=Functional test not support auto method functional_method_tip=Functional test not support auto method
#ldap #ldap
ldap_url_is_null=LDAP address is empty ldap_url_is_null=LDAP address is empty
ldap_dn_is_null=LDAP binding DN is empty ldap_dn_is_null=LDAP binding DN is empty
@ -136,4 +135,10 @@ login_fail_email_null=Login failed, user mailbox is empty
login_fail_ou_error=Login failed, please check the user OU login_fail_ou_error=Login failed, please check the user OU
login_fail_filter_error=Login failed, please check the user filter login_fail_filter_error=Login failed, please check the user filter
check_ldap_mapping=Check LDAP attribute mapping check_ldap_mapping=Check LDAP attribute mapping
ldap_mapping_value_null=LDAP user attribute mapping field is empty ldap_mapping_value_null=LDAP user attribute mapping field is empty
#quota
quota_workspace_excess_org_api=The total number of interface tests in the workspace cannot exceed the organization's quota
quota_workspace_excess_org_performance=The total number of performance tests for the workspace cannot exceed the organization's quota
quota_workspace_excess_org_max_threads=The maximum concurrent number of workspaces cannot exceed the quota of the organization
quota_workspace_excess_org_max_duration=The stress test duration of the workspace cannot exceed the organization's quota
quota_workspace_excess_org_resource_pool=The resource pool of the workspace cannot exceed the resource pool of the organization

View File

@ -118,7 +118,6 @@ test_case_already_exists_excel=导入文件中存在重复用例
test_case_module_already_exists=同层级下已存在该模块名称 test_case_module_already_exists=同层级下已存在该模块名称
api_test_name_already_exists=测试名称已经存在 api_test_name_already_exists=测试名称已经存在
functional_method_tip=功能测试不支持自动方式 functional_method_tip=功能测试不支持自动方式
#ldap #ldap
ldap_url_is_null=LDAP地址为空 ldap_url_is_null=LDAP地址为空
ldap_dn_is_null=LDAP绑定DN为空 ldap_dn_is_null=LDAP绑定DN为空
@ -137,5 +136,12 @@ login_fail_ou_error=登录失败请检查用户OU
login_fail_filter_error=登录失败,请检查用户过滤器 login_fail_filter_error=登录失败,请检查用户过滤器
check_ldap_mapping=检查LDAP属性映射 check_ldap_mapping=检查LDAP属性映射
ldap_mapping_value_null=LDAP用户属性映射字段为空值 ldap_mapping_value_null=LDAP用户属性映射字段为空值
#quota
quota_workspace_excess_org_api=工作空间的接口测试数量总和不能超过组织的配额
quota_workspace_excess_org_performance=工作空间的性能测试数量总和不能超过组织的配额
quota_workspace_excess_org_max_threads=工作空间的最大并发数不能超过组织的配额
quota_workspace_excess_org_max_duration=工作空间的压测时长不能超过组织的配额
quota_workspace_excess_org_resource_pool=工作空间的资源池不能超过组织的资源池范围

View File

@ -118,7 +118,6 @@ test_case_already_exists_excel=導入文件中存在重復用例
test_case_module_already_exists=同層級下已存在該模塊名稱 test_case_module_already_exists=同層級下已存在該模塊名稱
api_test_name_already_exists=測試名稱已經存在 api_test_name_already_exists=測試名稱已經存在
functional_method_tip=功能測試不支持自動方式 functional_method_tip=功能測試不支持自動方式
#ldap #ldap
ldap_url_is_null=LDAP地址為空 ldap_url_is_null=LDAP地址為空
ldap_dn_is_null=LDAP綁定DN為空 ldap_dn_is_null=LDAP綁定DN為空
@ -137,3 +136,9 @@ login_fail_ou_error=登錄失敗請檢查用戶OU
login_fail_filter_error=登錄失敗,請檢查用戶過濾器 login_fail_filter_error=登錄失敗,請檢查用戶過濾器
check_ldap_mapping=檢查LDAP屬性映射 check_ldap_mapping=檢查LDAP屬性映射
ldap_mapping_value_null=LDAP用戶屬性映射預設為空值 ldap_mapping_value_null=LDAP用戶屬性映射預設為空值
#quota
quota_workspace_excess_org_api=工作空間的接口測試數量總和不能超過組織的配額
quota_workspace_excess_org_performance=工作空間的性能測試數量總和不能超過組織的配額
quota_workspace_excess_org_max_threads=工作空間的最大並發數不能超過組織的配額
quota_workspace_excess_org_max_duration=工作空間的壓測時長不能超過組織的配額
quota_workspace_excess_org_resource_pool=工作空間的資源池不能超過組織的資源池範圍

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -1,16 +1,54 @@
<template> <template>
<div class="script-content"> <div >
<ms-code-edit mode="java" :read-only="isReadOnly" :data.sync="beanShellProcessor.script" theme="eclipse" :modes="['java']" ref="codeEdit"/> <el-row>
<el-col :span="22" class="script-content">
<ms-code-edit v-if="isCodeEditAlive" mode="java" :read-only="isReadOnly" :data.sync="beanShellProcessor.script" theme="eclipse" :modes="['java']" ref="codeEdit"/>
</el-col>
<el-col :span="2" class="script-index">
<div class="template-title">{{$t('api_test.request.processor.code_template')}}</div>
<div v-for="(template, index) in codeTemplates" :key="index" class="code-template">
<el-link @click="addTemplate(template)">{{template.title}}</el-link>
</div>
<div class="document-url">
<el-link href="https://jmeter.apache.org/usermanual/component_reference.html#BeanShell_PostProcessor" type="primary">{{$t('commons.reference_documentation')}}</el-link>
<ms-instructions-icon :content="$t('api_test.request.processor.bean_shell_processor_tip')"/>
</div>
</el-col>
</el-row>
</div> </div>
</template> </template>
<script> <script>
import MsCodeEdit from "../../../../common/components/MsCodeEdit"; import MsCodeEdit from "../../../../common/components/MsCodeEdit";
import MsInstructionsIcon from "../../../../common/components/MsInstructionsIcon";
export default { export default {
name: "MsBeanShellProcessor", name: "MsBeanShellProcessor",
components: {MsCodeEdit}, components: {MsInstructionsIcon, MsCodeEdit},
data() { data() {
return { return {
codeTemplates: [
{
title: this.$t('api_test.request.processor.code_template_get_variable'),
value: 'vars.get("variable_name");'
},
{
title: this.$t('api_test.request.processor.code_template_set_variable'),
value: 'vars.put("variable_name", "variable_value");'
},
{
title: this.$t('api_test.request.processor.code_template_get_response_header'),
value: 'prev.getResponseHeaders();'
},
{
title: this.$t('api_test.request.processor.code_template_get_response_code'),
value: 'prev.getResponseCode();'
},
{
title: this.$t('api_test.request.processor.code_template_get_response_result'),
value: 'prev.getResponseDataAsString();'
}
],
isCodeEditAlive: true
} }
}, },
props: { props: {
@ -25,6 +63,16 @@
type: Object, type: Object,
} }
}, },
methods: {
addTemplate(template) {
this.beanShellProcessor.script += template.value;
this.reload();
},
reload() {
this.isCodeEditAlive = false;
this.$nextTick(() => (this.isCodeEditAlive = true));
}
}
} }
</script> </script>
@ -35,8 +83,28 @@
} }
.script-content { .script-content {
padding: 15px 0; height: calc(100vh - 570px);
height: 300px; }
.script-index {
padding: 0 20px;
}
.script-index div:first-child {
font-weight: bold;
font-size: 15px;
}
.template-title {
margin-bottom: 5px;
}
.document-url {
margin-top: 10px;
}
.instructions-icon {
margin-left: 5px;
} }
</style> </style>

View File

@ -44,6 +44,12 @@
<el-tab-pane :label="$t('api_test.request.extract.label')" name="extract"> <el-tab-pane :label="$t('api_test.request.extract.label')" name="extract">
<ms-api-extract :is-read-only="isReadOnly" :extract="request.extract"/> <ms-api-extract :is-read-only="isReadOnly" :extract="request.extract"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('api_test.request.processor.pre_exec_script')" name="beanShellPreProcessor">
<ms-bean-shell-processor :is-read-only="isReadOnly" :bean-shell-processor="request.beanShellPreProcessor"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.processor.post_exec_script')" name="beanShellPostProcessor">
<ms-bean-shell-processor :is-read-only="isReadOnly" :bean-shell-processor="request.beanShellPostProcessor"/>
</el-tab-pane>
</el-tabs> </el-tabs>
</el-form> </el-form>
</template> </template>
@ -59,10 +65,12 @@
import MsDubboRegistryCenter from "@/business/components/api/test/components/request/dubbo/RegistryCenter"; import MsDubboRegistryCenter from "@/business/components/api/test/components/request/dubbo/RegistryCenter";
import MsDubboConfigCenter from "@/business/components/api/test/components/request/dubbo/ConfigCenter"; import MsDubboConfigCenter from "@/business/components/api/test/components/request/dubbo/ConfigCenter";
import MsDubboConsumerService from "@/business/components/api/test/components/request/dubbo/ConsumerAndService"; import MsDubboConsumerService from "@/business/components/api/test/components/request/dubbo/ConsumerAndService";
import MsBeanShellProcessor from "../processor/BeanShellProcessor";
export default { export default {
name: "MsApiDubboRequestForm", name: "MsApiDubboRequestForm",
components: { components: {
MsBeanShellProcessor,
MsDubboConsumerService, MsDubboConsumerService,
MsDubboConfigCenter, MsDubboConfigCenter,
MsDubboRegistryCenter, MsDubboRegistryCenter,
@ -134,4 +142,6 @@
color: #F56C6C; color: #F56C6C;
} }
</style> </style>

View File

@ -68,10 +68,10 @@
<el-tab-pane :label="$t('api_test.request.extract.label')" name="extract"> <el-tab-pane :label="$t('api_test.request.extract.label')" name="extract">
<ms-api-extract :is-read-only="isReadOnly" :extract="request.extract"/> <ms-api-extract :is-read-only="isReadOnly" :extract="request.extract"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="'预执行脚本'" name="beanShellPreProcessor"> <el-tab-pane :label="$t('api_test.request.processor.pre_exec_script')" name="beanShellPreProcessor">
<ms-bean-shell-processor :is-read-only="isReadOnly" :bean-shell-processor="request.beanShellPreProcessor"/> <ms-bean-shell-processor :is-read-only="isReadOnly" :bean-shell-processor="request.beanShellPreProcessor"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="'后执行脚本'" name="beanShellPostProcessor"> <el-tab-pane :label="$t('api_test.request.processor.post_exec_script')" name="beanShellPostProcessor">
<ms-bean-shell-processor :is-read-only="isReadOnly" :bean-shell-processor="request.beanShellPostProcessor"/> <ms-bean-shell-processor :is-read-only="isReadOnly" :bean-shell-processor="request.beanShellPostProcessor"/>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>

View File

@ -423,10 +423,7 @@ export class BeanShellPreProcessor extends BeanShellProcessor {
} }
export class BeanShellPostProcessor extends BeanShellProcessor { export class BeanShellPostProcessor extends BeanShellProcessor {
constructor(testName, script) { constructor(testName, processor) {
let processor = {
script: script,
};
super('BeanShellPostProcessor', 'TestBeanGUI', 'BeanShellPostProcessor', testName, processor) super('BeanShellPostProcessor', 'TestBeanGUI', 'BeanShellPostProcessor', testName, processor)
} }
} }

View File

@ -1,5 +1,5 @@
import { import {
Arguments, BeanShellPreProcessor, Arguments, BeanShellPostProcessor, BeanShellPreProcessor,
CookieManager, CookieManager,
DubboSample, DubboSample,
DurationAssertion, DurationAssertion,
@ -381,6 +381,8 @@ export class DubboRequest extends Request {
// Scenario.dubboConfig // Scenario.dubboConfig
this.dubboConfig = undefined; this.dubboConfig = undefined;
this.debugReport = undefined; this.debugReport = undefined;
this.beanShellPreProcessor = new BeanShellProcessor(options.beanShellPreProcessor);
this.beanShellPostProcessor = new BeanShellProcessor(options.beanShellPostProcessor);
this.sets({args: KeyValue, attachmentArgs: KeyValue}, options); this.sets({args: KeyValue, attachmentArgs: KeyValue}, options);
} }
@ -831,9 +833,10 @@ class JMXGenerator {
} else { } else {
this.addRequestBody(sampler, request); this.addRequestBody(sampler, request);
} }
this.addBeanShellProcessor(sampler, request);
} }
this.addBeanShellProcessor(sampler, request);
this.addRequestAssertion(sampler, request); this.addRequestAssertion(sampler, request);
this.addRequestExtractor(sampler, request); this.addRequestExtractor(sampler, request);
@ -900,13 +903,13 @@ class JMXGenerator {
} }
} }
addBeanShellProcessor(httpSamplerProxy, request) { addBeanShellProcessor(sampler, request) {
let name = request.name; let name = request.name;
if (request.beanShellPreProcessor && request.beanShellPreProcessor.script) { if (request.beanShellPreProcessor && request.beanShellPreProcessor.script) {
httpSamplerProxy.put(new BeanShellPreProcessor(name, request.beanShellPreProcessor)); sampler.put(new BeanShellPreProcessor(name, request.beanShellPreProcessor));
} }
if (request.beanShellPostProcessor && request.beanShellPostProcessor.script) { if (request.beanShellPostProcessor && request.beanShellPostProcessor.script) {
httpSamplerProxy.put(new BeanShellPreProcessor(name, request.beanShellPostProcessor)); sampler.put(new BeanShellPostProcessor(name, request.beanShellPostProcessor));
} }
} }

View File

@ -0,0 +1,53 @@
<template>
<el-tooltip class="instructions-icon" :effect="effect" :placement="placement">
<template v-slot:content>
{{content}}
</template>
<i :style="{'font-size': size + 'px'}" class="el-icon-info"></i>
</el-tooltip>
</template>
<script>
export default {
name: "MsInstructionsIcon",
props: {
content: String,
icon: {
type: String,
default: 'el-icon-question'
},
placement: {
type: String,
default: 'top-start'
},
type: {
type: String,
default: null
},
effect: {
type: String,
default: 'dark'
},
size: {
type: String,
default: '16'
},
isTesterPermission: {
type: Boolean,
default: false
}
},
}
</script>
<style scoped>
.el-icon-info {
color: #606266;
}
.el-icon-info:hover {
color: #409EFF;
}
</style>

View File

@ -1,49 +1,52 @@
<template> <template>
<el-card class="header-title" v-loading="result.loading"> <el-card class="header-title" v-loading="result.loading">
<div> <div>
<div>{{$t('organization.select_defect_platform')}}</div> <div>{{$t('organization.integration.select_defect_platform')}}</div>
<el-radio-group v-model="platform" style="margin-top: 10px" @change="change"> <el-radio-group v-model="platform" style="margin-top: 10px" @change="change">
<el-radio v-for="(item, index) in platforms" :key="index" :label="item.value" size="small"> <el-radio label="Tapd">
{{item.name}} <img class="platform" src="../../../../assets/tapd.png" alt="Tapd"/>
</el-radio>
<el-radio label="Jira">
<img class="platform" src="../../../../assets/jira.png" alt="Jira"/>
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
<div style="width: 500px"> <div style="width: 500px">
<div style="margin-top: 20px;margin-bottom: 10px">{{$t('organization.basic_auth_info')}}</div> <div style="margin-top: 20px;margin-bottom: 10px">{{$t('organization.integration.basic_auth_info')}}</div>
<el-form :model="form" ref="form" label-width="100px" size="small" :disabled="show" :rules="rules"> <el-form :model="form" ref="form" label-width="120px" size="small" :disabled="show" :rules="rules">
<el-form-item :label="$t('organization.api_account')" prop="account"> <el-form-item :label="$t('organization.integration.api_account')" prop="account">
<el-input v-model="form.account" :placeholder="$t('organization.input_api_account')"/> <el-input v-model="form.account" :placeholder="$t('organization.integration.input_api_account')"/>
</el-form-item> </el-form-item>
<el-form-item :label="$t('organization.api_password')" prop="password"> <el-form-item :label="$t('organization.integration.api_password')" prop="password">
<el-input v-model="form.password" auto-complete="new-password" <el-input v-model="form.password" auto-complete="new-password"
:placeholder="$t('organization.input_api_password')" show-password/> :placeholder="$t('organization.integration.input_api_password')" show-password/>
</el-form-item> </el-form-item>
<el-form-item label="JIRA 地址" prop="url" v-if="platform === 'Jira'"> <el-form-item :label="$t('organization.integration.jira_url')" prop="url" v-if="platform === 'Jira'">
<el-input v-model="form.url" placeholder="请输入Jira地址"/> <el-input v-model="form.url" :placeholder="$t('organization.integration.input_jira_url')"/>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
<div style="margin-left: 100px"> <div style="margin-left: 120px">
<el-button type="primary" size="mini" :disabled="!show" @click="testConnection">{{$t('ldap.test_connect')}} <el-button type="primary" size="mini" :disabled="!show" @click="testConnection">{{$t('ldap.test_connect')}}
</el-button> </el-button>
<el-button v-if="showEdit" size="mini" @click="edit">{{$t('commons.edit')}}</el-button> <el-button v-if="showEdit" size="mini" @click="edit">{{$t('commons.edit')}}</el-button>
<el-button type="primary" v-if="showSave" size="mini" @click="save('form')">{{$t('commons.save')}}</el-button> <el-button type="primary" v-if="showSave" size="mini" @click="save('form')">{{$t('commons.save')}}</el-button>
<el-button v-if="showCancel" size="mini" @click="cancelEdit">取消编辑</el-button> <el-button v-if="showCancel" size="mini" @click="cancelEdit">{{$t('organization.integration.cancel_edit')}}</el-button>
<el-button type="info" size="mini" @click="cancelIntegration('form')" :disabled="!show"> <el-button type="info" size="mini" @click="cancelIntegration('form')" :disabled="!show">
取消集成 {{$t('organization.integration.cancel_integration')}}
</el-button> </el-button>
</div> </div>
<div class="defect-tip"> <div class="defect-tip">
<div>{{$t('organization.use_tip')}}</div> <div>{{$t('organization.integration.use_tip')}}</div>
<div> <div>
1. {{$t('organization.use_tip_one')}} 1. {{$t('organization.integration.use_tip_one')}}
</div> </div>
<div> <div>
2. {{$t('organization.use_tip_two')}} 2. {{$t('organization.integration.use_tip_two')}}
<router-link to="/track/project/all" style="margin-left: 5px">{{$t('organization.link_the_project_now')}} <router-link to="/track/project/all" style="margin-left: 5px">{{$t('organization.integration.link_the_project_now')}}
</router-link> </router-link>
</div> </div>
</div> </div>
@ -65,20 +68,10 @@
showEdit: true, showEdit: true,
showSave: false, showSave: false,
showCancel: false, showCancel: false,
platforms: [
{
name: 'TAPD',
value: 'Tapd',
},
{
name: 'JIRA',
value: 'Jira',
}
],
rules: { rules: {
account: {required: true, message: this.$t('organization.input_api_account'), trigger: ['change', 'blur']}, account: {required: true, message: this.$t('organization.integration.input_api_account'), trigger: ['change', 'blur']},
password: {required: true, message: this.$t('organization.input_api_password'), trigger: ['change', 'blur']}, password: {required: true, message: this.$t('organization.integration.input_api_password'), trigger: ['change', 'blur']},
url: {required: true, message: '请输入url', trigger: ['change', 'blur']} url: {required: true, message: this.$t('organization.integration.input_jira_url'), trigger: ['change', 'blur']}
}, },
} }
}, },
@ -119,7 +112,7 @@
cancelIntegration() { cancelIntegration() {
if (this.form.account && this.form.password && this.platform) { if (this.form.account && this.form.password && this.platform) {
this.$alert("确认取消集成 " + this.platform + "", '', { this.$alert(this.$t('organization.integration.cancel_confirm') + this.platform + "", '', {
confirmButtonText: this.$t('commons.confirm'), confirmButtonText: this.$t('commons.confirm'),
callback: (action) => { callback: (action) => {
if (action === 'confirm') { if (action === 'confirm') {
@ -127,19 +120,19 @@
param.orgId = getCurrentUser().lastOrganizationId; param.orgId = getCurrentUser().lastOrganizationId;
param.platform = this.platform; param.platform = this.platform;
this.result = this.$post("service/integration/delete", param, () => { this.result = this.$post("service/integration/delete", param, () => {
this.$success("操作成功"); this.$success(this.$t('organization.integration.successful_operation'));
this.init(''); this.init('');
}); });
} }
} }
}); });
} else { } else {
this.$warning("未集成该平台!"); this.$warning(this.$t('organization.integration.not_integrated'));
} }
}, },
save(form) { save(form) {
if (!this.platform) { if (!this.platform) {
this.$warning("请选择集成的平台!"); this.$warning(this.$t('organization.integration.choose_platform'));
return; return;
} }
let param = {}; let param = {};
@ -196,7 +189,7 @@
}, },
testConnection() { testConnection() {
this.result = this.$get("issues/auth/" + this.platform, () => { this.result = this.$get("issues/auth/" + this.platform, () => {
this.$success("验证通过!"); this.$success(this.$t('organization.integration.verified'));
}); });
} }
} }
@ -215,4 +208,9 @@
padding: 10px; padding: 10px;
border-radius: 3px; border-radius: 3px;
} }
.platform {
height: 90px;
vertical-align: middle
}
</style> </style>

View File

@ -66,6 +66,9 @@
<el-form-item :label="$t('member.new_password')" prop="newpassword"> <el-form-item :label="$t('member.new_password')" prop="newpassword">
<el-input v-model="ruleForm.newpassword" autocomplete="off" show-password/> <el-input v-model="ruleForm.newpassword" autocomplete="off" show-password/>
</el-form-item> </el-form-item>
<el-form-item :label="$t('member.repeat_password')" prop="repeatPassword">
<el-input v-model="ruleForm.repeatPassword" autocomplete="off" show-password/>
</el-form-item>
</el-form> </el-form>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<ms-dialog-footer <ms-dialog-footer
@ -139,6 +142,15 @@
message: this.$t('member.password_format_is_incorrect'), message: this.$t('member.password_format_is_incorrect'),
trigger: 'blur' trigger: 'blur'
}, },
],
repeatPassword: [
{required: true, message: this.$t('user.input_password'), trigger: 'blur'},
{
required: true,
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,30}$/,
message: this.$t('member.password_format_is_incorrect'),
trigger: 'blur'
},
] ]
} }
} }
@ -188,6 +200,10 @@
updatePassword(editPasswordForm) { updatePassword(editPasswordForm) {
this.$refs[editPasswordForm].validate(valid => { this.$refs[editPasswordForm].validate(valid => {
if (valid) { if (valid) {
if (this.ruleForm.newpassword !== this.ruleForm.repeatPassword) {
this.$warning(this.$t('member.inconsistent_passwords'));
return;
}
this.result = this.$post(this.updatePasswordPath, this.ruleForm, response => { this.result = this.$post(this.updatePasswordPath, this.ruleForm, response => {
this.$success(this.$t('commons.modify_success')); this.$success(this.$t('commons.modify_success'));
this.editPasswordVisible = false; this.editPasswordVisible = false;

View File

@ -61,6 +61,7 @@
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<div style="text-align: center"> {{testCases.length}} </div>
</el-main> </el-main>
</el-container> </el-container>
</el-container> </el-container>
@ -161,6 +162,8 @@
if (this.selectNodeIds && this.selectNodeIds.length > 0) { if (this.selectNodeIds && this.selectNodeIds.length > 0) {
// param.nodeIds = this.selectNodeIds; // param.nodeIds = this.selectNodeIds;
this.condition.nodeIds = this.selectNodeIds; this.condition.nodeIds = this.selectNodeIds;
} else {
this.condition.nodeIds = [];
} }
this.result = this.$post('/test/case/name', this.condition, response => { this.result = this.$post('/test/case/name', this.condition, response => {
this.testCases = response.data; this.testCases = response.data;

View File

@ -108,6 +108,7 @@ export default {
formatErr: 'Format Error', formatErr: 'Format Error',
id: 'ID', id: 'ID',
please_upload: 'Please upload file', please_upload: 'Please upload file',
reference_documentation: "Reference documentation",
date: { date: {
select_date: 'Select date', select_date: 'Select date',
start_date: 'Start date', start_date: 'Start date',
@ -177,16 +178,27 @@ export default {
select: 'Select Organization', select: 'Select Organization',
service_integration: 'Service integration', service_integration: 'Service integration',
defect_manage: 'Defect management platform', defect_manage: 'Defect management platform',
select_defect_platform: 'Please select the defect management platform to be integrated:', integration: {
basic_auth_info: 'Basic Auth account information:', select_defect_platform: 'Please select the defect management platform to be integrated:',
api_account: 'API account', basic_auth_info: 'Basic Auth account information:',
api_password: 'API password', api_account: 'API account',
input_api_account: 'please enter account', api_password: 'API password',
input_api_password: 'Please enter password', jira_url: 'JIRA url',
use_tip: 'Usage guidelines:', input_api_account: 'please enter account',
use_tip_one: 'Basic Auth account information is queried in "Company Management-Security and Integration-Open Platform"', input_api_password: 'Please enter password',
use_tip_two: 'After saving the Basic Auth account information, you need to manually associate the ID/key in the Metersphere project', input_jira_url: 'Please enter Jira address, for example: https://metersphere.atlassian.net/',
link_the_project_now: 'Link the project now', use_tip: 'Usage guidelines:',
use_tip_one: 'Basic Auth account information is queried in "Company Management-Security and Integration-Open Platform"',
use_tip_two: 'After saving the Basic Auth account information, you need to manually associate the ID/key in the Metersphere project',
link_the_project_now: 'Link the project now',
cancel_edit: 'Cancel edit',
cancel_integration: 'Cancel integration',
cancel_confirm: 'Confirm cancellation of integration ',
successful_operation: 'Successful operation',
not_integrated: 'The platform is not integrated',
choose_platform: 'Please choose an integrated platform',
verified: 'Verified'
}
}, },
project: { project: {
name: 'Project name', name: 'Project name',
@ -219,6 +231,8 @@ export default {
password_format_is_incorrect: 'Valid password: 8-30 digits, English upper and lower case letters + numbers + special characters (optional)', password_format_is_incorrect: 'Valid password: 8-30 digits, English upper and lower case letters + numbers + special characters (optional)',
old_password: 'Old Password', old_password: 'Old Password',
new_password: 'New Password', new_password: 'New Password',
repeat_password: 'Repeat',
inconsistent_passwords: 'The two passwords entered are inconsistent',
remove_member: 'Are you sure you want to remove this member', remove_member: 'Are you sure you want to remove this member',
input_id_or_email: 'Please enter user ID, or user Email', input_id_or_email: 'Please enter user ID, or user Email',
no_such_user: 'Without this user information, please enter the correct user ID or user Email!', no_such_user: 'Without this user information, please enter the correct user ID or user Email!',
@ -446,6 +460,17 @@ export default {
json_path_expression: "JSONPath expression", json_path_expression: "JSONPath expression",
xpath_expression: "XPath expression", xpath_expression: "XPath expression",
}, },
processor: {
pre_exec_script : "PreProcessor",
post_exec_script: "PostProcessor",
code_template: "Code template",
bean_shell_processor_tip: "Currently only BeanShell scripts are supported",
code_template_get_variable: "Get variable",
code_template_set_variable: "Set variable",
code_template_get_response_header: "Get response header",
code_template_get_response_code: "Get response code",
code_template_get_response_result: "Get response result"
},
dubbo: { dubbo: {
protocol: "protocol", protocol: "protocol",
input_interface: "Please enter the interface", input_interface: "Please enter the interface",
@ -804,5 +829,7 @@ export default {
modify: "Modify Quota", modify: "Modify Quota",
edit_quota_title: "{0} quota", edit_quota_title: "{0} quota",
workspace_quota_list: "Workspace quota list of {0}", workspace_quota_list: "Workspace quota list of {0}",
unlimited: "Unlimited",
clean: "Clean"
} }
}; };

View File

@ -107,6 +107,7 @@ export default {
please_upload: '请上传文件', please_upload: '请上传文件',
formatErr: '格式错误', formatErr: '格式错误',
please_save: '请先保存', please_save: '请先保存',
reference_documentation: "参考文档",
id: 'ID', id: 'ID',
date: { date: {
select_date: '选择日期', select_date: '选择日期',
@ -178,16 +179,27 @@ export default {
delete_warning: '删除该组织将同步删除该组织下所有相关工作空间和相关工作空间下的所有项目,以及项目中的所有用例、接口测试、性能测试等,确定要删除吗?', delete_warning: '删除该组织将同步删除该组织下所有相关工作空间和相关工作空间下的所有项目,以及项目中的所有用例、接口测试、性能测试等,确定要删除吗?',
service_integration: '服务集成', service_integration: '服务集成',
defect_manage: '缺陷管理平台', defect_manage: '缺陷管理平台',
select_defect_platform: '请选择要集成的缺陷管理平台:', integration: {
basic_auth_info: 'Basic Auth 账号信息:', select_defect_platform: '请选择要集成的缺陷管理平台:',
api_account: 'API 账号', basic_auth_info: 'Basic Auth 账号信息:',
api_password: 'API 口令', api_account: 'API 账号',
input_api_account: '请输入账号', api_password: 'API 口令',
input_api_password: '请输入口令', jira_url: 'JIRA 地址',
use_tip: '使用指引:', input_api_account: '请输入账号',
use_tip_one: 'Basic Auth 账号信息在"公司管理-安全与集成-开放平台"中查询', input_api_password: '请输入口令',
use_tip_two: '保存 Basic Auth 账号信息后,需要在 Metersphere 项目中手动关联 ID/key', input_jira_url: '请输入Jira地址https://metersphere.atlassian.net/',
link_the_project_now: '马上关联项目', use_tip: '使用指引:',
use_tip_one: 'Basic Auth 账号信息在"公司管理-安全与集成-开放平台"中查询',
use_tip_two: '保存 Basic Auth 账号信息后,需要在 Metersphere 项目中手动关联 ID/key',
link_the_project_now: '马上关联项目',
cancel_edit: '取消编辑',
cancel_integration: '取消集成',
cancel_confirm: '确认取消集成 ',
successful_operation: '操作成功',
not_integrated: '未集成该平台',
choose_platform: '请选择集成的平台',
verified: '验证通过'
}
}, },
project: { project: {
recent: '最近的项目', recent: '最近的项目',
@ -219,6 +231,8 @@ export default {
password_format_is_incorrect: '有效密码8-30位英文大小写字母+数字+特殊字符(可选)', password_format_is_incorrect: '有效密码8-30位英文大小写字母+数字+特殊字符(可选)',
old_password: '旧密码', old_password: '旧密码',
new_password: '新密码', new_password: '新密码',
repeat_password: '确认密码',
inconsistent_passwords: '两次输入的密码不一致',
remove_member: '确定要移除该成员吗', remove_member: '确定要移除该成员吗',
input_id_or_email: '请输入用户 ID, 或者 用户邮箱', input_id_or_email: '请输入用户 ID, 或者 用户邮箱',
no_such_user: '无此用户信息, 请输入正确的用户 ID 或者 用户邮箱!', no_such_user: '无此用户信息, 请输入正确的用户 ID 或者 用户邮箱!',
@ -447,6 +461,17 @@ export default {
json_path_expression: "JSONPath表达式", json_path_expression: "JSONPath表达式",
xpath_expression: "XPath表达式", xpath_expression: "XPath表达式",
}, },
processor: {
pre_exec_script : "预执行脚本",
post_exec_script: "后执行脚本",
code_template: "代码模版",
bean_shell_processor_tip: "仅支持 BeanShell 脚本",
code_template_get_variable: "获取变量",
code_template_set_variable: "设置变量",
code_template_get_response_header: "获取响应头",
code_template_get_response_code: "获取响应码",
code_template_get_response_result: "获取响应结果"
},
dubbo: { dubbo: {
protocol: "协议", protocol: "协议",
input_interface: "请输入Interface", input_interface: "请输入Interface",
@ -806,5 +831,7 @@ export default {
modify: "修改配额", modify: "修改配额",
edit_quota_title: "{0}的配额", edit_quota_title: "{0}的配额",
workspace_quota_list: "{0}的工作空间配额列表", workspace_quota_list: "{0}的工作空间配额列表",
unlimited: "无限制",
clean: "清空"
} }
}; };

View File

@ -105,6 +105,7 @@ export default {
formatErr: '格式錯誤', formatErr: '格式錯誤',
please_save: '請先保存', please_save: '請先保存',
id: 'ID', id: 'ID',
reference_documentation: "參考文檔",
please_upload: '請上傳文件', please_upload: '請上傳文件',
date: { date: {
select_date: '選擇日期', select_date: '選擇日期',
@ -176,16 +177,27 @@ export default {
delete_warning: '删除该组织将同步删除该组织下所有相关工作空间和相关工作空间下的所有项目,以及项目中的所有用例、接口测试、性能测试等,确定要删除吗?', delete_warning: '删除该组织将同步删除该组织下所有相关工作空间和相关工作空间下的所有项目,以及项目中的所有用例、接口测试、性能测试等,确定要删除吗?',
service_integration: '服務集成', service_integration: '服務集成',
defect_manage: '缺陷管理平台', defect_manage: '缺陷管理平台',
select_defect_platform: '請選擇要集成的缺陷管理平台:', integration: {
basic_auth_info: 'Basic Auth 賬號信息:', select_defect_platform: '請選擇要集成的缺陷管理平台:',
api_account: 'API 賬號', basic_auth_info: 'Basic Auth 賬號信息:',
api_password: 'API 口令', api_account: 'API 賬號',
input_api_account: '請輸入賬號', api_password: 'API 口令',
input_api_password: '請輸入口令', jira_url: 'JIRA 地址',
use_tip: '使用指引:', input_api_account: '請輸入賬號',
use_tip_one: 'Basic Auth 賬號信息在"公司管理-安全與集成-開放平台"中查詢', input_api_password: '請輸入口令',
use_tip_two: '保存 Basic Auth 賬號信息後,需要在 Metersphere 項目中手動關聯 ID/key', input_jira_url: '請輸入Jira地址https://metersphere.atlassian.net/',
link_the_project_now: '馬上關聯項目', use_tip: '使用指引:',
use_tip_one: 'Basic Auth 賬號信息在"公司管理-安全與集成-開放平台"中查詢',
use_tip_two: '保存 Basic Auth 賬號信息後,需要在 Metersphere 項目中手動關聯 ID/key',
link_the_project_now: '馬上關聯項目',
cancel_edit: '取消編輯',
cancel_integration: '取消集成',
cancel_confirm: '確認取消集成 ',
successful_operation: '操作成功',
not_integrated: '未集成該平台',
choose_platform: '請選擇集成的平台',
verified: '驗證通過'
}
}, },
project: { project: {
recent: '最近的項目', recent: '最近的項目',
@ -217,6 +229,8 @@ export default {
password_format_is_incorrect: '有效密碼8-30 位,英文大小寫字母+數位+特殊字元(可選)', password_format_is_incorrect: '有效密碼8-30 位,英文大小寫字母+數位+特殊字元(可選)',
old_password: '舊密碼', old_password: '舊密碼',
new_password: '新密碼', new_password: '新密碼',
repeat_password: '確認密碼',
inconsistent_passwords: '兩次輸入的密碼不一致',
remove_member: '確定要移除該成員嗎', remove_member: '確定要移除該成員嗎',
input_id_or_email: '請輸入用戶 ID, 或者 用戶郵箱', input_id_or_email: '請輸入用戶 ID, 或者 用戶郵箱',
no_such_user: '無此用戶信息, 請輸入正確的用戶 ID 或者 用戶郵箱!', no_such_user: '無此用戶信息, 請輸入正確的用戶 ID 或者 用戶郵箱!',
@ -446,6 +460,17 @@ export default {
json_path_expression: "JSONPath運算式", json_path_expression: "JSONPath運算式",
xpath_expression: "XPath運算式", xpath_expression: "XPath運算式",
}, },
processor: {
pre_exec_script : "預執行腳本",
post_exec_script: "後執行腳本",
code_template: "代碼模版",
bean_shell_processor_tip: "僅支持 BeanShell 腳本",
code_template_get_variable: "獲取變量",
code_template_set_variable: "設置變量",
code_template_get_response_header: "獲取響應頭",
code_template_get_response_code: "獲取響應碼",
code_template_get_response_result: "獲取響應結果"
},
dubbo: { dubbo: {
protocol: "協定", protocol: "協定",
input_interface: "請輸入Interface", input_interface: "請輸入Interface",
@ -803,5 +828,7 @@ export default {
modify: "修改配額", modify: "修改配額",
edit_quota_title: "{0}的配額", edit_quota_title: "{0}的配額",
workspace_quota_list: "{0}的工作空間配額列表", workspace_quota_list: "{0}的工作空間配額列表",
unlimited: "無限制",
clean: "清空"
} }
}; };