excel导入导出国际化
This commit is contained in:
parent
f415a121a5
commit
6977ee496b
|
@ -2,14 +2,18 @@ package io.metersphere.config;
|
|||
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import org.hibernate.validator.HibernateValidator;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
|
||||
|
||||
import javax.validation.Validator;
|
||||
|
||||
|
||||
@Configuration
|
||||
public class I18nConfig {
|
||||
|
||||
|
@ -33,7 +37,14 @@ public class I18nConfig {
|
|||
@Bean
|
||||
public LocalValidatorFactoryBean localValidatorFactoryBean(MessageSource messageSource) {
|
||||
LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
|
||||
localValidatorFactoryBean.setProviderClass(HibernateValidator.class);
|
||||
localValidatorFactoryBean.setValidationMessageSource(messageSource);
|
||||
return localValidatorFactoryBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Validator validator(LocalValidatorFactoryBean localValidatorFactoryBean){
|
||||
return localValidatorFactoryBean.getValidator();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,33 +12,33 @@ import javax.validation.constraints.Pattern;
|
|||
@ColumnWidth(15)
|
||||
public class TestCaseExcelData {
|
||||
|
||||
@NotBlank
|
||||
@NotBlank(message = "{cannot_be_null}")
|
||||
@Length(max=50)
|
||||
@ExcelProperty("{test_case_name}")
|
||||
private String name;
|
||||
|
||||
@NotBlank
|
||||
@NotBlank(message = "{cannot_be_null}")
|
||||
@Length(max=1000)
|
||||
@ExcelProperty("{test_case_module}")
|
||||
@ColumnWidth(30)
|
||||
@Pattern(regexp = "^(?!.*//).*$", message = "{incorrect_format}")
|
||||
private String nodePath;
|
||||
|
||||
@NotBlank
|
||||
@NotBlank(message = "{cannot_be_null}")
|
||||
@ExcelProperty("{test_case_type}")
|
||||
@Pattern(regexp = "(^functional$)|(^performance$)|(^api$)", message = "{test_case_type_validate}")
|
||||
private String type;
|
||||
|
||||
@NotBlank
|
||||
@NotBlank(message = "{cannot_be_null}")
|
||||
@ExcelProperty("{test_case_maintainer}")
|
||||
private String maintainer;
|
||||
|
||||
@NotBlank
|
||||
@NotBlank(message = "{cannot_be_null}")
|
||||
@ExcelProperty("{test_case_priority}")
|
||||
@Pattern(regexp = "(^P0$)|(^P1$)|(^P2$)|(^P3$)", message = "{test_case_priority_validate}")
|
||||
private String priority;
|
||||
|
||||
@NotBlank
|
||||
@NotBlank(message = "{cannot_be_null}")
|
||||
@ExcelProperty("{test_case_method}")
|
||||
@Pattern(regexp = "(^manual$)|(^auto$)", message = "{test_case_method_validate}")
|
||||
private String method;
|
||||
|
|
|
@ -61,7 +61,7 @@ public abstract class EasyExcelListener <T> extends AnalysisEventListener<T> {
|
|||
|
||||
if (!StringUtils.isEmpty(errMsg)) {
|
||||
ExcelErrData excelErrData = new ExcelErrData(t, rowIndex,
|
||||
Translator.get("number") + rowIndex + Translator.get("row") + Translator.get("error")
|
||||
Translator.get("number")+ " " + rowIndex + " " + Translator.get("row") + Translator.get("error")
|
||||
+ ":" + errMsg);
|
||||
errList.add(excelErrData);
|
||||
} else {
|
||||
|
|
|
@ -7,6 +7,7 @@ import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
|||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.Validator;
|
||||
import javax.validation.groups.Default;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Set;
|
||||
|
@ -17,11 +18,11 @@ public class ExcelValidateHelper {
|
|||
private static ExcelValidateHelper excelValidateHelper;
|
||||
|
||||
@Resource
|
||||
LocalValidatorFactoryBean localValidatorFactoryBean;
|
||||
Validator validator;
|
||||
|
||||
public static <T> String validateEntity(T obj) throws NoSuchFieldException {
|
||||
StringBuilder result = new StringBuilder();
|
||||
Set<ConstraintViolation<T>> set = excelValidateHelper.localValidatorFactoryBean.getValidator().validate(obj, Default.class);
|
||||
Set<ConstraintViolation<T>> set = excelValidateHelper.validator.validate(obj, Default.class);
|
||||
if (set != null && !set.isEmpty()) {
|
||||
for (ConstraintViolation<T> cv : set) {
|
||||
Field declaredField = obj.getClass().getDeclaredField(cv.getPropertyPath().toString());
|
||||
|
@ -33,9 +34,12 @@ public class ExcelValidateHelper {
|
|||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 在静态方法中调用
|
||||
*/
|
||||
@PostConstruct
|
||||
public void initialize() {
|
||||
excelValidateHelper = this;
|
||||
excelValidateHelper.localValidatorFactoryBean = this.localValidatorFactoryBean;
|
||||
excelValidateHelper.validator = this.validator;
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ import io.metersphere.base.mapper.ext.ExtTestCaseMapper;
|
|||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.user.SessionUser;
|
||||
import io.metersphere.commons.utils.BeanUtils;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.commons.utils.SessionUtils;
|
||||
import io.metersphere.excel.domain.ExcelErrData;
|
||||
import io.metersphere.excel.domain.ExcelResponse;
|
||||
|
@ -190,6 +191,7 @@ public class TestCaseService {
|
|||
EasyExcelFactory.read(file.getInputStream(), TestCaseExcelData.class, easyExcelListener).sheet().doRead();
|
||||
errList = easyExcelListener.getErrList();
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
MSException.throwException(e.getMessage());
|
||||
} finally {
|
||||
easyExcelListener.close();
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#commons
|
||||
error_lang_invalid=Invalid language parameter
|
||||
file_cannot_be_null=File cannot be empty!
|
||||
cannot_be_null=\tCannot be empty
|
||||
number=Number
|
||||
row=row
|
||||
error=error
|
||||
#user related
|
||||
user_email_already_exists=User email already exists
|
||||
user_name_is_null=User name cannot be null
|
||||
|
@ -43,23 +47,20 @@ test_case_node_level=level
|
|||
test_case_node_level_tip=The node tree maximum depth is
|
||||
test_case_module_not_null=The owned module cannot be empty
|
||||
test_case_create_module_fail=Failed to create module
|
||||
test_case_import_template_name=Test case templates
|
||||
test_case_import_template_name=Test_case_templates
|
||||
test_case_import_template_sheet=Template
|
||||
module_not_null=The module must not be blank
|
||||
user_not_exists=The user in this workspace is not exists
|
||||
test_case_already_exists=The test case in this project is exists
|
||||
parse_data_error=Parse data error
|
||||
missing_header_information=Missing header information
|
||||
number=Number
|
||||
row=row
|
||||
error=error
|
||||
test_case_exist=A test case already exists under this project:
|
||||
node_deep_limit=The node depth does not exceed 5 layers!
|
||||
before_delete_plan=There is an associated test case under this plan, please unlink it first!
|
||||
incorrect_format=Incorrect format
|
||||
test_case_type_validate=must be functional, performance, api
|
||||
test_case_priority_validate=must be P0, P1, P2, P3
|
||||
test_case_method_validate=must be manual, auto
|
||||
incorrect_format=\tincorrect format
|
||||
test_case_type_validate=\tmust be functional, performance, api
|
||||
test_case_priority_validate=\tmust be P0, P1, P2, P3
|
||||
test_case_method_validate=\tmust be manual, auto
|
||||
test_case_name=Name
|
||||
test_case_type=Type
|
||||
test_case_maintainer=Maintainer
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#commons
|
||||
error_lang_invalid=语言参数错误
|
||||
file_cannot_be_null=文件不能为空!
|
||||
cannot_be_null=不能为空
|
||||
number=第
|
||||
row=行
|
||||
error=出错
|
||||
#user related
|
||||
user_email_already_exists=用户邮箱已存在
|
||||
user_name_is_null=用户名不能为空
|
||||
|
@ -50,9 +54,6 @@ user_not_exists=该工作空间下无该用户
|
|||
test_case_already_exists=该项目下已存在该测试用例
|
||||
parse_data_error=解析数据出错
|
||||
missing_header_information=缺少头部信息
|
||||
number=第
|
||||
row=行
|
||||
error=出错
|
||||
test_case_exist=该项目下已存在用例:
|
||||
node_deep_limit=节点深度不超过5层!
|
||||
before_delete_plan=该计划下存在关联测试用例,请先取消关联!
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#commons
|
||||
error_lang_invalid=語言參數錯誤
|
||||
file_cannot_be_null=文件不能為空!
|
||||
cannot_be_null=不能為空
|
||||
number=第
|
||||
row=行
|
||||
error=出錯
|
||||
#user related
|
||||
user_email_already_exists=用戶郵箱已存在
|
||||
user_name_is_null=用戶名不能為空
|
||||
|
@ -50,9 +54,6 @@ user_not_exists=該工作空間下無該用戶
|
|||
test_case_already_exists=該項目下已存在該測試用例
|
||||
parse_data_error=解析數據出錯
|
||||
missing_header_information=缺少頭部信息
|
||||
number=第
|
||||
row=行
|
||||
error=出錯
|
||||
test_case_exist=該項目下已存在用例:
|
||||
node_deep_limit=節點深度不超過5層!
|
||||
before_delete_plan=該計劃下存在關聯測試用例,請先取消關聯!
|
||||
|
|
|
@ -135,9 +135,9 @@
|
|||
});
|
||||
},
|
||||
saveAndRun() {
|
||||
if (!this.validTestPlan()) {
|
||||
return;
|
||||
}
|
||||
// if (!this.validTestPlan()) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
let options = this.getSaveOption();
|
||||
|
||||
|
|
|
@ -4,21 +4,23 @@
|
|||
|
||||
<el-row>
|
||||
<el-link type="primary" class="download-template"
|
||||
href="/test/case/export/template">{{$t('test_track.case.import.download_template')}}</el-link></el-row>
|
||||
@click="downloadTemplate"
|
||||
>{{$t('test_track.case.import.download_template')}}</el-link></el-row>
|
||||
<el-row>
|
||||
<el-upload
|
||||
v-loading="isLoading"
|
||||
v-loading="result.loading"
|
||||
:element-loading-text="$t('test_track.case.import.importing')"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
class="upload-demo"
|
||||
:action="'/test/case/import/' + projectId"
|
||||
multiple
|
||||
:limit="1"
|
||||
action=""
|
||||
:on-exceed="handleExceed"
|
||||
:beforeUpload="UploadValidate"
|
||||
:on-success="handleSuccess"
|
||||
:on-error="handleError"
|
||||
:show-file-list="false"
|
||||
:http-request="upload"
|
||||
:file-list="fileList">
|
||||
<template v-slot:trigger>
|
||||
<el-button size="mini" type="success" plain>{{$t('test_track.case.import.click_upload')}}</el-button>
|
||||
|
@ -49,6 +51,7 @@
|
|||
components: {ElUploadList, MsTableButton},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
dialogVisible: false,
|
||||
fileList: [],
|
||||
errList: [],
|
||||
|
@ -80,16 +83,16 @@
|
|||
return true;
|
||||
},
|
||||
handleSuccess(response) {
|
||||
this.isLoading = false;
|
||||
let res = response.data;
|
||||
if (res.success) {
|
||||
this.$success(this.$t('test_track.case.import.success'));
|
||||
this.dialogVisible = false;
|
||||
this.$emit("refresh");
|
||||
} else {
|
||||
this.errList = res.errList;
|
||||
}
|
||||
this.fileList = [];
|
||||
|
||||
// let res = response.data;
|
||||
// if (res.success) {
|
||||
// this.$success(this.$t('test_track.case.import.success'));
|
||||
// this.dialogVisible = false;
|
||||
// this.$emit("refresh");
|
||||
// } else {
|
||||
// this.errList = res.errList;
|
||||
// }
|
||||
// this.fileList = [];
|
||||
},
|
||||
handleError(err, file, fileList) {
|
||||
this.isLoading = false;
|
||||
|
@ -102,6 +105,28 @@
|
|||
open() {
|
||||
this.dialogVisible = true;
|
||||
},
|
||||
downloadTemplate() {
|
||||
// this.$get('/test/case/export/template');
|
||||
// fileDownload('/test/case/export/template', {});
|
||||
this.$fileDownload('/test/case/export/template');
|
||||
},
|
||||
upload(file) {
|
||||
this.isLoading = false;
|
||||
this.fileList.push(file.file);
|
||||
this.result = this.$fileUpload('/test/case/import/' + this.projectId, this.fileList,response => {
|
||||
let res = response.data;
|
||||
if (res.success) {
|
||||
this.$success(this.$t('test_track.case.import.success'));
|
||||
this.dialogVisible = false;
|
||||
this.$emit("refresh");
|
||||
} else {
|
||||
this.errList = res.errList;
|
||||
}
|
||||
this.fileList = [];
|
||||
}, erro => {
|
||||
this.fileList = [];
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -35,8 +35,7 @@ export default {
|
|||
function then(success, response, result) {
|
||||
if (!response.data) {
|
||||
success(response);
|
||||
}
|
||||
if (response.data.success) {
|
||||
} else if (response.data.success) {
|
||||
success(response.data);
|
||||
} else {
|
||||
window.console.warn(response.data);
|
||||
|
@ -108,5 +107,40 @@ export default {
|
|||
if (array.length < 1) return;
|
||||
axios.all(array).then(axios.spread(callback));
|
||||
};
|
||||
|
||||
Vue.prototype.$fileDownload = function(url) {
|
||||
axios({
|
||||
method: 'get',
|
||||
url: url,
|
||||
responseType: 'blob',
|
||||
}).then(response => {
|
||||
let fileName = window.decodeURI(response.headers['content-disposition'].split('=')[1]);
|
||||
let link = document.createElement("a");
|
||||
link.href = window.URL.createObjectURL(new Blob([response.data], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"}));
|
||||
link.download = fileName;
|
||||
link.click();
|
||||
})
|
||||
};
|
||||
|
||||
Vue.prototype.$fileUpload = function(url, fileList, success, failure) {
|
||||
let result = {loading: true};
|
||||
let formData = new FormData();
|
||||
if (fileList.length > 0) {
|
||||
fileList.forEach(f => {
|
||||
formData.append("file", f);
|
||||
});
|
||||
}
|
||||
axios.post(url, formData, { headers: { "Content-Type": "multipart/form-data" }})
|
||||
.then(response => {
|
||||
then(success, response, result);
|
||||
}).catch(error => {
|
||||
exception(error, result);
|
||||
if (failure) {
|
||||
then(failure, error, result);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue