Merge branch 'v1.1' of https://github.com/metersphere/server into v1.1
This commit is contained in:
commit
d7df95c7f6
|
@ -102,9 +102,9 @@ public class PerformanceTestController {
|
||||||
return performanceTestService.run(request);
|
return performanceTestService.run(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("stop/{reportId}")
|
@GetMapping("stop/{reportId}/{forceStop}")
|
||||||
public void stopTest(@PathVariable String reportId) {
|
public void stopTest(@PathVariable String reportId, @PathVariable boolean forceStop) {
|
||||||
performanceTestService.stopTest(reportId);
|
performanceTestService.stopTest(reportId, forceStop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/file/metadata/{testId}")
|
@GetMapping("/file/metadata/{testId}")
|
||||||
|
|
|
@ -401,7 +401,19 @@ public class PerformanceTestService {
|
||||||
scheduleService.addOrUpdateCronJob(request, PerformanceTestJob.getJobKey(request.getResourceId()), PerformanceTestJob.getTriggerKey(request.getResourceId()), PerformanceTestJob.class);
|
scheduleService.addOrUpdateCronJob(request, PerformanceTestJob.getJobKey(request.getResourceId()), PerformanceTestJob.getTriggerKey(request.getResourceId()), PerformanceTestJob.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopTest(String reportId) {
|
public void stopTest(String reportId, boolean forceStop) {
|
||||||
|
if (forceStop) {
|
||||||
reportService.deleteReport(reportId);
|
reportService.deleteReport(reportId);
|
||||||
|
} else {
|
||||||
|
LoadTestReport loadTestReport = loadTestReportMapper.selectByPrimaryKey(reportId);
|
||||||
|
LoadTestWithBLOBs loadTest = loadTestMapper.selectByPrimaryKey(loadTestReport.getTestId());
|
||||||
|
final Engine engine = EngineFactory.createEngine(loadTest);
|
||||||
|
if (engine == null) {
|
||||||
|
MSException.throwException(String.format("Stop report fail. create engine fail,report ID:%s", reportId));
|
||||||
|
}
|
||||||
|
reportService.stopEngine(loadTest, engine);
|
||||||
|
// 停止测试之后设置报告的状态
|
||||||
|
reportService.updateStatus(reportId, PerformanceTestStatus.Completed.name());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ public class ReportService {
|
||||||
loadTestReportMapper.deleteByPrimaryKey(reportId);
|
loadTestReportMapper.deleteByPrimaryKey(reportId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopEngine(LoadTestWithBLOBs loadTest, Engine engine) {
|
public void stopEngine(LoadTestWithBLOBs loadTest, Engine engine) {
|
||||||
engine.stop();
|
engine.stop();
|
||||||
loadTest.setStatus(PerformanceTestStatus.Saved.name());
|
loadTest.setStatus(PerformanceTestStatus.Saved.name());
|
||||||
loadTestMapper.updateByPrimaryKeySelective(loadTest);
|
loadTestMapper.updateByPrimaryKeySelective(loadTest);
|
||||||
|
@ -239,4 +239,11 @@ public class ReportService {
|
||||||
public LoadTestReport getReport(String reportId) {
|
public LoadTestReport getReport(String reportId) {
|
||||||
return loadTestReportMapper.selectByPrimaryKey(reportId);
|
return loadTestReportMapper.selectByPrimaryKey(reportId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateStatus(String reportId, String status) {
|
||||||
|
LoadTestReport report = new LoadTestReport();
|
||||||
|
report.setId(reportId);
|
||||||
|
report.setStatus(status);
|
||||||
|
loadTestReportMapper.updateByPrimaryKeySelective(report);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,9 @@ public class ReportWebSocket {
|
||||||
session.close();
|
session.close();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (!session.isOpen()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (PerformanceTestStatus.Running.name().equals(report.getStatus())) {
|
if (PerformanceTestStatus.Running.name().equals(report.getStatus())) {
|
||||||
session.getBasicRemote().sendText("refresh-" + this.refresh++);
|
session.getBasicRemote().sendText("refresh-" + this.refresh++);
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,14 +146,17 @@
|
||||||
</root>
|
</root>
|
||||||
|
|
||||||
<logger name="io.metersphere" additivity="false">
|
<logger name="io.metersphere" additivity="false">
|
||||||
<level value="${logger.level:INFO}" />
|
<level value="${logger.level:INFO}"/>
|
||||||
<appender-ref ref="infoAsyncAppender" />
|
<appender-ref ref="infoAsyncAppender"/>
|
||||||
<appender-ref ref="warnAsyncAppender" />
|
<appender-ref ref="warnAsyncAppender"/>
|
||||||
<appender-ref ref="errorAsyncAppender" />
|
<appender-ref ref="errorAsyncAppender"/>
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
<logger name="io.metersphere.Application" additivity="false" level="${logger.level:INFO}">
|
<logger name="io.metersphere.Application" additivity="false" level="${logger.level:INFO}">
|
||||||
<appender-ref ref="infoAsyncAppender" />
|
<appender-ref ref="infoAsyncAppender"/>
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
|
<logger name="com.alibaba.nacos.naming.client.listener" additivity="false" level="ERROR"/>
|
||||||
|
<logger name="org.apache.dubbo.registry.nacos.NacosRegistry" additivity="false" level="ERROR"/>
|
||||||
|
|
||||||
</configuration>
|
</configuration>
|
|
@ -14,11 +14,11 @@
|
||||||
</el-breadcrumb>
|
</el-breadcrumb>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row class="ms-report-view-btns">
|
<el-row class="ms-report-view-btns">
|
||||||
<el-button :disabled="isReadOnly || status !== 'Running'" type="primary" plain size="mini"
|
<el-button :disabled="isReadOnly || report.status !== 'Running'" type="primary" plain size="mini"
|
||||||
@click="stopTest(reportId)">
|
@click="dialogFormVisible=true">
|
||||||
{{$t('report.test_stop_now')}}
|
{{$t('report.test_stop_now')}}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button :disabled="isReadOnly || status !== 'Completed'" type="success" plain size="mini"
|
<el-button :disabled="isReadOnly || report.status !== 'Completed'" type="success" plain size="mini"
|
||||||
@click="rerun(testId)">
|
@click="rerun(testId)">
|
||||||
{{$t('report.test_execute_again')}}
|
{{$t('report.test_execute_again')}}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
@ -62,6 +62,16 @@
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
|
|
||||||
</el-card>
|
</el-card>
|
||||||
|
<el-dialog :title="$t('report.test_stop_now_confirm')" :visible.sync="dialogFormVisible" width="30%">
|
||||||
|
<p v-html="$t('report.force_stop_tips')"></p>
|
||||||
|
<p v-html="$t('report.stop_tips')"></p>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button type="danger" size="small" @click="stopTest(true)">{{$t('report.force_stop_btn')}}
|
||||||
|
</el-button>
|
||||||
|
<el-button type="primary" size="small" @click="stopTest(false)">{{$t('report.stop_btn')}}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
</ms-main-container>
|
</ms-main-container>
|
||||||
</ms-container>
|
</ms-container>
|
||||||
</template>
|
</template>
|
||||||
|
@ -103,7 +113,8 @@
|
||||||
title: 'Logging',
|
title: 'Logging',
|
||||||
report: {},
|
report: {},
|
||||||
isReadOnly: false,
|
isReadOnly: false,
|
||||||
websocket: null
|
websocket: null,
|
||||||
|
dialogFormVisible: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -156,7 +167,7 @@
|
||||||
this.$warning(this.$t('report.generation_error'));
|
this.$warning(this.$t('report.generation_error'));
|
||||||
break;
|
break;
|
||||||
case 'Starting':
|
case 'Starting':
|
||||||
this.$warning(this.$t('report.start_status'));
|
this.$alert(this.$t('report.start_status'));
|
||||||
break;
|
break;
|
||||||
case 'Reporting':
|
case 'Reporting':
|
||||||
case 'Running':
|
case 'Running':
|
||||||
|
@ -171,18 +182,16 @@
|
||||||
this.minutes = '0';
|
this.minutes = '0';
|
||||||
this.seconds = '0';
|
this.seconds = '0';
|
||||||
},
|
},
|
||||||
stopTest(reportId) {
|
stopTest(forceStop) {
|
||||||
this.$confirm(this.$t('report.test_stop_now_confirm'), '', {
|
this.result = this.$get('/performance/stop/' + this.reportId + '/' + forceStop, () => {
|
||||||
confirmButtonText: this.$t('commons.confirm'),
|
|
||||||
cancelButtonText: this.$t('commons.cancel'),
|
|
||||||
type: 'warning'
|
|
||||||
}).then(() => {
|
|
||||||
this.result = this.$get('/performance/stop/' + reportId, () => {
|
|
||||||
this.$success(this.$t('report.test_stop_success'));
|
this.$success(this.$t('report.test_stop_success'));
|
||||||
|
if (forceStop) {
|
||||||
this.$router.push('/performance/report/all');
|
this.$router.push('/performance/report/all');
|
||||||
|
} else {
|
||||||
|
this.report.status = 'Completed';
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}).catch(() => {
|
this.dialogFormVisible = false;
|
||||||
});
|
|
||||||
},
|
},
|
||||||
rerun(testId) {
|
rerun(testId) {
|
||||||
this.$confirm(this.$t('report.test_rerun_confirm'), '', {
|
this.$confirm(this.$t('report.test_rerun_confirm'), '', {
|
||||||
|
@ -190,26 +199,32 @@
|
||||||
cancelButtonText: this.$t('commons.cancel'),
|
cancelButtonText: this.$t('commons.cancel'),
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.result = this.$post('/performance/run', {id: testId, triggerMode: 'MANUAL'}, () => {
|
this.result = this.$post('/performance/run', {id: testId, triggerMode: 'MANUAL'}, (response) => {
|
||||||
this.$success(this.$t('load_test.is_running'))
|
this.reportId = response.data;
|
||||||
this.$router.push({path: '/performance/report/all'})
|
this.$router.push({path: '/performance/report/view/' + this.reportId})
|
||||||
|
// 注册 socket
|
||||||
|
this.initWebSocket();
|
||||||
})
|
})
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onOpen() {
|
onOpen() {
|
||||||
window.console.log("open WebSocket");
|
window.console.log("socket opening.");
|
||||||
},
|
},
|
||||||
onError(e) {
|
onError(e) {
|
||||||
window.console.error(e)
|
window.console.error(e)
|
||||||
},
|
},
|
||||||
onMessage(e) {
|
onMessage(e) {
|
||||||
this.$set(this.report, "refresh", e.data); // 触发刷新
|
this.$set(this.report, "refresh", e.data); // 触发刷新
|
||||||
|
this.$set(this.report, "status", 'Running');
|
||||||
this.initReportTimeInfo();
|
this.initReportTimeInfo();
|
||||||
|
window.console.log('receive a message:', e.data);
|
||||||
},
|
},
|
||||||
onClose(e) {
|
onClose(e) {
|
||||||
this.$set(this.report, "refresh", e.data); // 触发刷新
|
this.$set(this.report, "refresh", Math.random()); // 触发刷新
|
||||||
|
this.$set(this.report, "status", 'Completed');
|
||||||
this.initReportTimeInfo();
|
this.initReportTimeInfo();
|
||||||
|
window.console.log("socket closed.");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
|
|
@ -153,6 +153,9 @@
|
||||||
watch: {
|
watch: {
|
||||||
report: {
|
report: {
|
||||||
handler(val) {
|
handler(val) {
|
||||||
|
if (!val.status || !val.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let status = val.status;
|
let status = val.status;
|
||||||
this.id = val.id;
|
this.id = val.id;
|
||||||
if (status === "Completed" || status === "Running") {
|
if (status === "Completed" || status === "Running") {
|
||||||
|
|
|
@ -80,6 +80,9 @@
|
||||||
watch: {
|
watch: {
|
||||||
report: {
|
report: {
|
||||||
handler(val) {
|
handler(val) {
|
||||||
|
if (!val.status || !val.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let status = val.status;
|
let status = val.status;
|
||||||
this.id = val.id;
|
this.id = val.id;
|
||||||
if (status === "Completed" || status === "Running") {
|
if (status === "Completed" || status === "Running") {
|
||||||
|
|
|
@ -162,6 +162,9 @@
|
||||||
watch: {
|
watch: {
|
||||||
report: {
|
report: {
|
||||||
handler(val){
|
handler(val){
|
||||||
|
if (!val.status || !val.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let status = val.status;
|
let status = val.status;
|
||||||
this.id = val.id;
|
this.id = val.id;
|
||||||
if (status === "Completed" || status === "Running") {
|
if (status === "Completed" || status === "Running") {
|
||||||
|
|
|
@ -325,6 +325,9 @@
|
||||||
watch: {
|
watch: {
|
||||||
report: {
|
report: {
|
||||||
handler(val) {
|
handler(val) {
|
||||||
|
if (!val.status || !val.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let status = val.status;
|
let status = val.status;
|
||||||
this.id = val.id;
|
this.id = val.id;
|
||||||
if (status === "Completed" || status === "Running") {
|
if (status === "Completed" || status === "Running") {
|
||||||
|
|
|
@ -4,11 +4,13 @@
|
||||||
<el-card v-loading="result.loading">
|
<el-card v-loading="result.loading">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="10">
|
<el-col :span="10">
|
||||||
<el-input :disabled="isReadOnly" :placeholder="$t('load_test.input_name')" v-model="testPlan.name" class="input-with-select"
|
<el-input :disabled="isReadOnly" :placeholder="$t('load_test.input_name')" v-model="testPlan.name"
|
||||||
|
class="input-with-select"
|
||||||
maxlength="30" show-word-limit
|
maxlength="30" show-word-limit
|
||||||
>
|
>
|
||||||
<template v-slot:prepend>
|
<template v-slot:prepend>
|
||||||
<el-select :disabled="isReadOnly" v-model="testPlan.projectId" :placeholder="$t('load_test.select_project')">
|
<el-select :disabled="isReadOnly" v-model="testPlan.projectId"
|
||||||
|
:placeholder="$t('load_test.select_project')">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in projects"
|
v-for="item in projects"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
|
@ -21,10 +23,13 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" :offset="2">
|
<el-col :span="12" :offset="2">
|
||||||
<el-button :disabled="isReadOnly" type="primary" plain @click="save">{{$t('commons.save')}}</el-button>
|
<el-button :disabled="isReadOnly" type="primary" plain @click="save">{{$t('commons.save')}}</el-button>
|
||||||
<el-button :disabled="isReadOnly" type="primary" plain @click="saveAndRun">{{$t('load_test.save_and_run')}}</el-button>
|
<el-button :disabled="isReadOnly" type="primary" plain @click="saveAndRun">
|
||||||
|
{{$t('load_test.save_and_run')}}
|
||||||
|
</el-button>
|
||||||
<el-button :disabled="isReadOnly" type="warning" plain @click="cancel">{{$t('commons.cancel')}}</el-button>
|
<el-button :disabled="isReadOnly" type="warning" plain @click="cancel">{{$t('commons.cancel')}}</el-button>
|
||||||
|
|
||||||
<ms-schedule-config :schedule="testPlan.schedule" :save="saveCronExpression" @scheduleChange="saveSchedule" :check-open="checkScheduleEdit" :custom-validate="durationValidate"/>
|
<ms-schedule-config :schedule="testPlan.schedule" :save="saveCronExpression" @scheduleChange="saveSchedule"
|
||||||
|
:check-open="checkScheduleEdit" :custom-validate="durationValidate"/>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
|
@ -34,7 +39,8 @@
|
||||||
<performance-basic-config :is-read-only="isReadOnly" :test-plan="testPlan" ref="basicConfig"/>
|
<performance-basic-config :is-read-only="isReadOnly" :test-plan="testPlan" ref="basicConfig"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="$t('load_test.pressure_config')">
|
<el-tab-pane :label="$t('load_test.pressure_config')">
|
||||||
<performance-pressure-config :is-read-only="isReadOnly" :test-plan="testPlan" :test-id="testId" ref="pressureConfig" @changeActive="changeTabActive"/>
|
<performance-pressure-config :is-read-only="isReadOnly" :test-plan="testPlan" :test-id="testId"
|
||||||
|
ref="pressureConfig" @changeActive="changeTabActive"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="$t('load_test.advanced_config')" class="advanced-config">
|
<el-tab-pane :label="$t('load_test.advanced_config')" class="advanced-config">
|
||||||
<performance-advanced-config :read-only="isReadOnly" :test-id="testId" ref="advancedConfig"/>
|
<performance-advanced-config :read-only="isReadOnly" :test-id="testId" ref="advancedConfig"/>
|
||||||
|
@ -67,7 +73,7 @@
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
result: {},
|
result: {},
|
||||||
testPlan: {schedule:{}},
|
testPlan: {schedule: {}},
|
||||||
listProjectPath: "/project/listAll",
|
listProjectPath: "/project/listAll",
|
||||||
savePath: "/performance/save",
|
savePath: "/performance/save",
|
||||||
editPath: "/performance/edit",
|
editPath: "/performance/edit",
|
||||||
|
@ -177,9 +183,9 @@
|
||||||
this.result = this.$request(options, (response) => {
|
this.result = this.$request(options, (response) => {
|
||||||
this.testPlan.id = response.data;
|
this.testPlan.id = response.data;
|
||||||
this.$success(this.$t('commons.save_success'));
|
this.$success(this.$t('commons.save_success'));
|
||||||
this.result = this.$post(this.runPath, {id: this.testPlan.id, triggerMode: 'MANUAL'}, () => {
|
this.result = this.$post(this.runPath, {id: this.testPlan.id, triggerMode: 'MANUAL'}, (response) => {
|
||||||
this.$success(this.$t('load_test.is_running'))
|
let reportId = response.data;
|
||||||
this.$router.push({path: '/performance/report/all'})
|
this.$router.push({path: '/performance/report/view/' + reportId})
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -249,7 +255,7 @@
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
changeTabActive(activeName) {
|
changeTabActive(activeName) {
|
||||||
this.$nextTick(()=> {
|
this.$nextTick(() => {
|
||||||
this.active = activeName;
|
this.active = activeName;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -258,10 +258,14 @@ export default {
|
||||||
generation_error: 'Report generation error, cannot be viewed!',
|
generation_error: 'Report generation error, cannot be viewed!',
|
||||||
being_generated: 'Report is being generated...',
|
being_generated: 'Report is being generated...',
|
||||||
delete_confirm: 'Confirm delete: ',
|
delete_confirm: 'Confirm delete: ',
|
||||||
start_status: 'The test is starting, please check the report later!',
|
start_status: 'The test is in the beginning state, we will automatically display it on the page after we generate the report!',
|
||||||
run_status: 'The test is running, please check the report later!',
|
run_status: 'The test is running, please check the report later!',
|
||||||
user_name: 'Creator',
|
user_name: 'Creator',
|
||||||
project_name: 'Project Name'
|
project_name: 'Project Name',
|
||||||
|
force_stop_tips: '<strong>Terminating</strong> the servers will immediately kill the servers and the JTL files will be lost.',
|
||||||
|
stop_tips: 'A <strong>Graceful shutdown</strong> will archive the JTL files and then stop the servers.',
|
||||||
|
force_stop_btn: 'Terminating',
|
||||||
|
stop_btn: 'Graceful shutdown',
|
||||||
},
|
},
|
||||||
load_test: {
|
load_test: {
|
||||||
operating: 'Operating',
|
operating: 'Operating',
|
||||||
|
|
|
@ -256,11 +256,14 @@ export default {
|
||||||
generation_error: '报告生成错误,无法查看!',
|
generation_error: '报告生成错误,无法查看!',
|
||||||
being_generated: '报告正在生成中...',
|
being_generated: '报告正在生成中...',
|
||||||
delete_confirm: '确认删除报告: ',
|
delete_confirm: '确认删除报告: ',
|
||||||
start_status: '测试处于开始状态,请稍后查看报告!',
|
start_status: '测试处于开始状态, 我们生成报告后会自动展示到页面上!',
|
||||||
run_status: '测试处于运行状态,请稍后查看报告!',
|
run_status: '测试处于运行状态,请稍后查看报告!',
|
||||||
user_name: '创建人',
|
user_name: '创建人',
|
||||||
project_name: '所属项目',
|
project_name: '所属项目',
|
||||||
|
force_stop_tips: '<strong>强制停止</strong>测试会立刻结束当前测试并删除报告数据',
|
||||||
|
stop_tips: '<strong>停止</strong>测试会结束当前测试并保留报告数据',
|
||||||
|
force_stop_btn: '强制停止',
|
||||||
|
stop_btn: '停止',
|
||||||
},
|
},
|
||||||
load_test: {
|
load_test: {
|
||||||
operating: '操作',
|
operating: '操作',
|
||||||
|
|
|
@ -256,10 +256,14 @@ export default {
|
||||||
generation_error: '報告生成錯誤,無法查看!',
|
generation_error: '報告生成錯誤,無法查看!',
|
||||||
being_generated: '報告正在生成中...',
|
being_generated: '報告正在生成中...',
|
||||||
delete_confirm: '確認刪除報告: ',
|
delete_confirm: '確認刪除報告: ',
|
||||||
start_status: '測試處於開始狀態,請稍後查看報告!',
|
start_status: '測試處於開始狀態, 我們生成報告後會自動展示到頁面上!',
|
||||||
run_status: '測試處於運行狀態,請稍後查看報告!',
|
run_status: '測試處於運行狀態,請稍後查看報告!',
|
||||||
user_name: '創建人',
|
user_name: '創建人',
|
||||||
project_name: '所屬項目'
|
project_name: '所屬項目',
|
||||||
|
force_stop_tips: '<strong>強制停止</strong>測試會立刻結束當前測試並刪除報告數據',
|
||||||
|
stop_tips: '<strong>停止</strong>測試會結束當前測試並保留報告數據',
|
||||||
|
force_stop_btn: '強制停止',
|
||||||
|
stop_btn: '停止',
|
||||||
},
|
},
|
||||||
load_test: {
|
load_test: {
|
||||||
operating: '操作',
|
operating: '操作',
|
||||||
|
|
Loading…
Reference in New Issue