Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
d94f031a12
|
@ -17,15 +17,14 @@ import io.metersphere.controller.request.member.SetAdminRequest;
|
||||||
import io.metersphere.controller.request.organization.AddOrgMemberRequest;
|
import io.metersphere.controller.request.organization.AddOrgMemberRequest;
|
||||||
import io.metersphere.controller.request.organization.QueryOrgMemberRequest;
|
import io.metersphere.controller.request.organization.QueryOrgMemberRequest;
|
||||||
import io.metersphere.dto.UserDTO;
|
import io.metersphere.dto.UserDTO;
|
||||||
|
import io.metersphere.dto.UserRoleDTO;
|
||||||
import io.metersphere.service.OrganizationService;
|
import io.metersphere.service.OrganizationService;
|
||||||
import io.metersphere.service.UserService;
|
import io.metersphere.service.UserService;
|
||||||
import io.metersphere.service.WorkspaceService;
|
import io.metersphere.service.WorkspaceService;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.shiro.authz.annotation.Logical;
|
import org.apache.shiro.authz.annotation.Logical;
|
||||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||||
import org.springframework.beans.BeanUtils;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -54,6 +53,12 @@ public class UserController {
|
||||||
return PageUtils.setPageInfo(page, userService.getUserListWithRequest(request));
|
return PageUtils.setPageInfo(page, userService.getUserListWithRequest(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/special/user/role/{userId}")
|
||||||
|
@RequiresRoles(RoleConstants.ADMIN)
|
||||||
|
public UserRoleDTO getUserRole(@PathVariable("userId") String userId) {
|
||||||
|
return userService.getUserRole(userId);
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/special/delete/{userId}")
|
@GetMapping("/special/delete/{userId}")
|
||||||
@RequiresRoles(RoleConstants.ADMIN)
|
@RequiresRoles(RoleConstants.ADMIN)
|
||||||
public void deleteUser(@PathVariable(value = "userId") String userId) {
|
public void deleteUser(@PathVariable(value = "userId") String userId) {
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package io.metersphere.dto;
|
||||||
|
|
||||||
|
import io.metersphere.base.domain.Role;
|
||||||
|
import io.metersphere.base.domain.UserRole;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class UserRoleDTO {
|
||||||
|
|
||||||
|
private String userId;
|
||||||
|
private List<Role> roles;
|
||||||
|
private List<UserRole> userRoles;
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
}
|
|
@ -14,52 +14,52 @@ public class TestCaseExcelData {
|
||||||
|
|
||||||
@NotBlank
|
@NotBlank
|
||||||
@Length(max=50)
|
@Length(max=50)
|
||||||
@ExcelProperty("用例名称")
|
@ExcelProperty("{test_case_name}")
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@NotBlank
|
@NotBlank
|
||||||
@Length(max=1000)
|
@Length(max=1000)
|
||||||
@ExcelProperty("所属模块")
|
@ExcelProperty("{test_case_module}")
|
||||||
@ColumnWidth(30)
|
@ColumnWidth(30)
|
||||||
@Pattern(regexp = "^(?!.*//).*$", message = "{incorrect_format}")
|
@Pattern(regexp = "^(?!.*//).*$", message = "{incorrect_format}")
|
||||||
private String nodePath;
|
private String nodePath;
|
||||||
|
|
||||||
@NotBlank
|
@NotBlank
|
||||||
@ExcelProperty("用例类型")
|
@ExcelProperty("{test_case_type}")
|
||||||
@Pattern(regexp = "(^functional$)|(^performance$)|(^api$)", message = "{test_case_type_validate}")
|
@Pattern(regexp = "(^functional$)|(^performance$)|(^api$)", message = "{test_case_type_validate}")
|
||||||
private String type;
|
private String type;
|
||||||
|
|
||||||
@NotBlank
|
@NotBlank
|
||||||
@ExcelProperty("维护人")
|
@ExcelProperty("{test_case_maintainer}")
|
||||||
private String maintainer;
|
private String maintainer;
|
||||||
|
|
||||||
@NotBlank
|
@NotBlank
|
||||||
@ExcelProperty("优先级")
|
@ExcelProperty("{test_case_priority}")
|
||||||
@Pattern(regexp = "(^P0$)|(^P1$)|(^P2$)|(^P3$)", message = "{test_case_priority_validate}")
|
@Pattern(regexp = "(^P0$)|(^P1$)|(^P2$)|(^P3$)", message = "{test_case_priority_validate}")
|
||||||
private String priority;
|
private String priority;
|
||||||
|
|
||||||
@NotBlank
|
@NotBlank
|
||||||
@ExcelProperty("测试方式")
|
@ExcelProperty("{test_case_method}")
|
||||||
@Pattern(regexp = "(^manual$)|(^auto$)", message = "{test_case_method_validate}")
|
@Pattern(regexp = "(^manual$)|(^auto$)", message = "{test_case_method_validate}")
|
||||||
private String method;
|
private String method;
|
||||||
|
|
||||||
@ColumnWidth(50)
|
@ColumnWidth(50)
|
||||||
@ExcelProperty("前置条件")
|
@ExcelProperty("{test_case_prerequisite}")
|
||||||
@Length(min=0, max=1000)
|
@Length(min=0, max=1000)
|
||||||
private String prerequisite;
|
private String prerequisite;
|
||||||
|
|
||||||
@ColumnWidth(50)
|
@ColumnWidth(50)
|
||||||
@ExcelProperty("备注")
|
@ExcelProperty("{test_case_remark}")
|
||||||
@Length(max=1000)
|
@Length(max=1000)
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
@ColumnWidth(50)
|
@ColumnWidth(50)
|
||||||
@ExcelProperty("步骤描述")
|
@ExcelProperty("{test_case_step_desc}")
|
||||||
@Length(max=1000)
|
@Length(max=1000)
|
||||||
private String stepDesc;
|
private String stepDesc;
|
||||||
|
|
||||||
@ColumnWidth(50)
|
@ColumnWidth(50)
|
||||||
@ExcelProperty("预期结果")
|
@ExcelProperty("{test_case_step_result}")
|
||||||
@Length(max=1000)
|
@Length(max=1000)
|
||||||
private String stepResult;
|
private String stepResult;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,24 +6,22 @@ import com.alibaba.excel.event.AnalysisEventListener;
|
||||||
import com.alibaba.excel.exception.ExcelAnalysisException;
|
import com.alibaba.excel.exception.ExcelAnalysisException;
|
||||||
import com.alibaba.excel.util.StringUtils;
|
import com.alibaba.excel.util.StringUtils;
|
||||||
import io.metersphere.commons.utils.LogUtil;
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
import io.metersphere.excel.utils.ExcelValidateHelper;
|
|
||||||
import io.metersphere.excel.domain.ExcelErrData;
|
import io.metersphere.excel.domain.ExcelErrData;
|
||||||
|
import io.metersphere.excel.utils.EasyExcelI18nTranslator;
|
||||||
|
import io.metersphere.excel.utils.ExcelValidateHelper;
|
||||||
import io.metersphere.i18n.Translator;
|
import io.metersphere.i18n.Translator;
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import java.lang.reflect.*;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@Component
|
|
||||||
public abstract class EasyExcelListener <T> extends AnalysisEventListener<T> {
|
public abstract class EasyExcelListener <T> extends AnalysisEventListener<T> {
|
||||||
|
|
||||||
protected List<ExcelErrData<T>> errList = new ArrayList<>();
|
protected List<ExcelErrData<T>> errList = new ArrayList<>();
|
||||||
|
|
||||||
protected List<T> list = new ArrayList<>();
|
protected List<T> list = new ArrayList<>();
|
||||||
|
|
||||||
|
protected EasyExcelI18nTranslator easyExcelI18nTranslator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 每隔2000条存储数据库,然后清理list ,方便内存回收
|
* 每隔2000条存储数据库,然后清理list ,方便内存回收
|
||||||
*/
|
*/
|
||||||
|
@ -31,16 +29,15 @@ public abstract class EasyExcelListener <T> extends AnalysisEventListener<T> {
|
||||||
|
|
||||||
protected Class<T> clazz;
|
protected Class<T> clazz;
|
||||||
|
|
||||||
@Resource
|
|
||||||
ExcelValidateHelper excelValidateHelper;
|
|
||||||
|
|
||||||
public EasyExcelListener(){
|
public EasyExcelListener(){
|
||||||
Type type = getClass().getGenericSuperclass();
|
Type type = getClass().getGenericSuperclass();
|
||||||
this.clazz = (Class<T>) ((ParameterizedType) type).getActualTypeArguments()[0];
|
this.clazz = (Class<T>) ((ParameterizedType) type).getActualTypeArguments()[0];
|
||||||
|
this.easyExcelI18nTranslator = new EasyExcelI18nTranslator(this.clazz);
|
||||||
|
this.easyExcelI18nTranslator.translateExcelProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 这个每一条数据解析都会来调用
|
* 每条数据解析都会调用
|
||||||
*
|
*
|
||||||
* @param t
|
* @param t
|
||||||
* @param analysisContext
|
* @param analysisContext
|
||||||
|
@ -51,7 +48,7 @@ public abstract class EasyExcelListener <T> extends AnalysisEventListener<T> {
|
||||||
Integer rowIndex = analysisContext.readRowHolder().getRowIndex();
|
Integer rowIndex = analysisContext.readRowHolder().getRowIndex();
|
||||||
try {
|
try {
|
||||||
//根据excel数据实体中的javax.validation + 正则表达式来校验excel数据
|
//根据excel数据实体中的javax.validation + 正则表达式来校验excel数据
|
||||||
errMsg = excelValidateHelper.validateEntity(t);
|
errMsg = ExcelValidateHelper.validateEntity(t);
|
||||||
//自定义校验规则
|
//自定义校验规则
|
||||||
errMsg = validate(t, errMsg);
|
errMsg = validate(t, errMsg);
|
||||||
} catch (NoSuchFieldException e) {
|
} catch (NoSuchFieldException e) {
|
||||||
|
@ -104,7 +101,6 @@ public abstract class EasyExcelListener <T> extends AnalysisEventListener<T> {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
|
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
|
||||||
super.invokeHeadMap(headMap, context);
|
|
||||||
if (clazz != null){
|
if (clazz != null){
|
||||||
try {
|
try {
|
||||||
Set<String> fieldNameSet = getFieldNameSet(clazz);
|
Set<String> fieldNameSet = getFieldNameSet(clazz);
|
||||||
|
@ -118,6 +114,7 @@ public abstract class EasyExcelListener <T> extends AnalysisEventListener<T> {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
super.invokeHeadMap(headMap, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -142,11 +139,11 @@ public abstract class EasyExcelListener <T> extends AnalysisEventListener<T> {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<ExcelErrData<T>> getErrList() {
|
||||||
public List<ExcelErrData<T>> getAndClearErrList() {
|
return errList;
|
||||||
List<ExcelErrData<T>> tmp = this.errList;
|
|
||||||
this.errList = new ArrayList<>();
|
|
||||||
return tmp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void close () {
|
||||||
|
this.easyExcelI18nTranslator.resetExcelProperty();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -2,26 +2,23 @@ package io.metersphere.excel.listener;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONArray;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import io.metersphere.excel.domain.TestCaseExcelData;
|
|
||||||
import io.metersphere.base.domain.TestCaseWithBLOBs;
|
import io.metersphere.base.domain.TestCaseWithBLOBs;
|
||||||
import io.metersphere.commons.constants.TestCaseConstants;
|
import io.metersphere.commons.constants.TestCaseConstants;
|
||||||
import io.metersphere.commons.utils.BeanUtils;
|
import io.metersphere.commons.utils.BeanUtils;
|
||||||
|
import io.metersphere.excel.domain.TestCaseExcelData;
|
||||||
import io.metersphere.i18n.Translator;
|
import io.metersphere.i18n.Translator;
|
||||||
import io.metersphere.track.service.TestCaseService;
|
import io.metersphere.track.service.TestCaseService;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@Component
|
|
||||||
public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
|
public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
|
||||||
|
|
||||||
@Resource
|
|
||||||
private TestCaseService testCaseService;
|
private TestCaseService testCaseService;
|
||||||
|
|
||||||
private String projectId;
|
private String projectId;
|
||||||
|
@ -30,13 +27,11 @@ public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
|
||||||
|
|
||||||
Set<String> userIds;
|
Set<String> userIds;
|
||||||
|
|
||||||
public TestCaseDataListener() {}
|
public TestCaseDataListener(TestCaseService testCaseService, String projectId, Set<String> testCaseNames, Set<String> userIds) {
|
||||||
|
this.testCaseService = testCaseService;
|
||||||
public TestCaseDataListener init(String projectId, Set<String> testCaseNames, Set<String> userIds) {
|
|
||||||
this.projectId = projectId;
|
this.projectId = projectId;
|
||||||
this.testCaseNames = testCaseNames;
|
this.testCaseNames = testCaseNames;
|
||||||
this.userIds = userIds;
|
this.userIds = userIds;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
package io.metersphere.excel.utils;
|
||||||
|
|
||||||
|
import com.alibaba.excel.EasyExcel;
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
|
import io.metersphere.excel.domain.TestCaseExcelData;
|
||||||
|
import io.metersphere.exception.ExcelException;
|
||||||
|
import io.metersphere.i18n.Translator;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationHandler;
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class EasyExcelExporter {
|
||||||
|
|
||||||
|
EasyExcelI18nTranslator easyExcelI18nTranslator;
|
||||||
|
|
||||||
|
public EasyExcelExporter() {
|
||||||
|
easyExcelI18nTranslator = new EasyExcelI18nTranslator(TestCaseExcelData.class);
|
||||||
|
easyExcelI18nTranslator.translateExcelProperty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void export(HttpServletResponse response, Class clazz, List data, String fileName, String sheetName) {
|
||||||
|
response.setContentType("application/vnd.ms-excel");
|
||||||
|
response.setCharacterEncoding("utf-8");
|
||||||
|
try {
|
||||||
|
response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xlsx");
|
||||||
|
EasyExcel.write(response.getOutputStream(), clazz).sheet(sheetName).doWrite(data);
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
LogUtil.error(e.getMessage(), e);
|
||||||
|
throw new ExcelException("Utf-8 encoding is not supported");
|
||||||
|
} catch (IOException e) {
|
||||||
|
LogUtil.error(e.getMessage(), e);
|
||||||
|
throw new ExcelException("IO exception");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
easyExcelI18nTranslator.resetExcelProperty();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
package io.metersphere.excel.utils;
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
|
import io.metersphere.excel.domain.TestCaseExcelData;
|
||||||
|
import io.metersphere.exception.ExcelException;
|
||||||
|
import io.metersphere.i18n.Translator;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationHandler;
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表头国际化
|
||||||
|
* 先调用 saveOriginalExcelProperty 存储原表头注解值
|
||||||
|
* 再调用 translateExcelProperty 获取国际化的值
|
||||||
|
* 最后调用 resetExcelProperty 重置为原来值,防止切换语言后无法国际化
|
||||||
|
*/
|
||||||
|
public class EasyExcelI18nTranslator {
|
||||||
|
|
||||||
|
private Map<String, List<String>> excelPropertyMap = new HashMap<>();
|
||||||
|
|
||||||
|
private Class clazz;
|
||||||
|
|
||||||
|
public EasyExcelI18nTranslator(Class clazz) {
|
||||||
|
this.clazz = clazz;
|
||||||
|
saveOriginalExcelProperty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readExcelProperty(Class clazz, BiConsumer<String, Map<String, Object>> operate) {
|
||||||
|
Field field;
|
||||||
|
Field[] fields = clazz.getDeclaredFields();
|
||||||
|
for (int i = 0; i < fields.length ; i++) {
|
||||||
|
try {
|
||||||
|
field = clazz.getDeclaredField(fields[i].getName());
|
||||||
|
field.setAccessible(true);
|
||||||
|
ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
|
||||||
|
if(excelProperty != null){
|
||||||
|
InvocationHandler invocationHandler = Proxy.getInvocationHandler(excelProperty);
|
||||||
|
Field fieldValue = invocationHandler.getClass().getDeclaredField("memberValues");
|
||||||
|
fieldValue.setAccessible(true);
|
||||||
|
Map<String, Object> memberValues = null;
|
||||||
|
try {
|
||||||
|
memberValues = (Map<String, Object>) fieldValue.get(invocationHandler);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
LogUtil.error(e.getMessage(), e);
|
||||||
|
throw new ExcelException(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
operate.accept(field.getName(), memberValues);
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveOriginalExcelProperty() {
|
||||||
|
readExcelProperty(clazz, (fieldName, memberValues) -> {
|
||||||
|
List<String> values = Arrays.asList((String [])memberValues.get("value"));
|
||||||
|
List<String> copyValues = new ArrayList<>();
|
||||||
|
values.forEach(value -> {
|
||||||
|
copyValues.add(value);
|
||||||
|
});
|
||||||
|
excelPropertyMap.put(fieldName, copyValues);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void translateExcelProperty() {
|
||||||
|
readExcelProperty(TestCaseExcelData.class, (fieldName, memberValues) -> {
|
||||||
|
String [] values = (String[]) memberValues.get("value");
|
||||||
|
for (int j = 0; j < values.length; j++) {
|
||||||
|
if (Pattern.matches("^\\{.+\\}$", values[j])) {
|
||||||
|
values[j] = Translator.get(values[j].substring(1, values[j].length() - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memberValues.put("value", values);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetExcelProperty() {
|
||||||
|
readExcelProperty(clazz, (fieldName, memberValues) -> {
|
||||||
|
String [] values = (String[]) memberValues.get("value");
|
||||||
|
List<String> list = excelPropertyMap.get(fieldName);
|
||||||
|
for (int j = 0; j < values.length; j++) {
|
||||||
|
values[j] = list.get(j);
|
||||||
|
}
|
||||||
|
memberValues.put("value", values);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,30 +0,0 @@
|
||||||
package io.metersphere.excel.utils;
|
|
||||||
|
|
||||||
import com.alibaba.excel.EasyExcel;
|
|
||||||
import io.metersphere.commons.utils.LogUtil;
|
|
||||||
import io.metersphere.exception.ExcelException;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class EasyExcelUtil {
|
|
||||||
|
|
||||||
public static void export(HttpServletResponse response, Class clazz, List data, String fileName, String sheetName) {
|
|
||||||
response.setContentType("application/vnd.ms-excel");
|
|
||||||
response.setCharacterEncoding("utf-8");
|
|
||||||
try {
|
|
||||||
response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xlsx");
|
|
||||||
EasyExcel.write(response.getOutputStream(), clazz).sheet(sheetName).doWrite(data);
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
throw new ExcelException("不支持UTF-8编码");
|
|
||||||
} catch (IOException e) {
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
throw new ExcelException("IO异常");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,6 +4,7 @@ import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.validation.ConstraintViolation;
|
import javax.validation.ConstraintViolation;
|
||||||
import javax.validation.groups.Default;
|
import javax.validation.groups.Default;
|
||||||
|
@ -13,14 +14,14 @@ import java.util.Set;
|
||||||
@Component
|
@Component
|
||||||
public class ExcelValidateHelper {
|
public class ExcelValidateHelper {
|
||||||
|
|
||||||
private ExcelValidateHelper(){}
|
private static ExcelValidateHelper excelValidateHelper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
LocalValidatorFactoryBean localValidatorFactoryBean;
|
LocalValidatorFactoryBean localValidatorFactoryBean;
|
||||||
|
|
||||||
public <T> String validateEntity(T obj) throws NoSuchFieldException {
|
public static <T> String validateEntity(T obj) throws NoSuchFieldException {
|
||||||
StringBuilder result = new StringBuilder();
|
StringBuilder result = new StringBuilder();
|
||||||
Set<ConstraintViolation<T>> set = localValidatorFactoryBean.getValidator().validate(obj, Default.class);
|
Set<ConstraintViolation<T>> set = excelValidateHelper.localValidatorFactoryBean.getValidator().validate(obj, Default.class);
|
||||||
if (set != null && !set.isEmpty()) {
|
if (set != null && !set.isEmpty()) {
|
||||||
for (ConstraintViolation<T> cv : set) {
|
for (ConstraintViolation<T> cv : set) {
|
||||||
Field declaredField = obj.getClass().getDeclaredField(cv.getPropertyPath().toString());
|
Field declaredField = obj.getClass().getDeclaredField(cv.getPropertyPath().toString());
|
||||||
|
@ -31,4 +32,10 @@ public class ExcelValidateHelper {
|
||||||
}
|
}
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void initialize() {
|
||||||
|
excelValidateHelper = this;
|
||||||
|
excelValidateHelper.localValidatorFactoryBean = this.localValidatorFactoryBean;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -17,13 +17,13 @@ import io.metersphere.controller.request.member.SetAdminRequest;
|
||||||
import io.metersphere.controller.request.organization.AddOrgMemberRequest;
|
import io.metersphere.controller.request.organization.AddOrgMemberRequest;
|
||||||
import io.metersphere.controller.request.organization.QueryOrgMemberRequest;
|
import io.metersphere.controller.request.organization.QueryOrgMemberRequest;
|
||||||
import io.metersphere.dto.UserDTO;
|
import io.metersphere.dto.UserDTO;
|
||||||
|
import io.metersphere.dto.UserRoleDTO;
|
||||||
import io.metersphere.i18n.Translator;
|
import io.metersphere.i18n.Translator;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
@ -100,16 +100,24 @@ public class UserService {
|
||||||
}
|
}
|
||||||
UserDTO userDTO = new UserDTO();
|
UserDTO userDTO = new UserDTO();
|
||||||
BeanUtils.copyProperties(user, userDTO);
|
BeanUtils.copyProperties(user, userDTO);
|
||||||
|
UserRoleDTO userRole = getUserRole(userId);
|
||||||
|
userDTO.setUserRoles(userRole.getUserRoles());
|
||||||
|
userDTO.setRoles(userRole.getRoles());
|
||||||
|
return userDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserRoleDTO getUserRole(String userId) {
|
||||||
|
UserRoleDTO userRoleDTO = new UserRoleDTO();
|
||||||
//
|
//
|
||||||
UserRoleExample userRoleExample = new UserRoleExample();
|
UserRoleExample userRoleExample = new UserRoleExample();
|
||||||
userRoleExample.createCriteria().andUserIdEqualTo(userId);
|
userRoleExample.createCriteria().andUserIdEqualTo(userId);
|
||||||
List<UserRole> userRoleList = userRoleMapper.selectByExample(userRoleExample);
|
List<UserRole> userRoleList = userRoleMapper.selectByExample(userRoleExample);
|
||||||
|
|
||||||
if (CollectionUtils.isEmpty(userRoleList)) {
|
if (CollectionUtils.isEmpty(userRoleList)) {
|
||||||
return userDTO;
|
return userRoleDTO;
|
||||||
}
|
}
|
||||||
// 设置 user_role
|
// 设置 user_role
|
||||||
userDTO.setUserRoles(userRoleList);
|
userRoleDTO.setUserRoles(userRoleList);
|
||||||
|
|
||||||
List<String> roleIds = userRoleList.stream().map(UserRole::getRoleId).collect(Collectors.toList());
|
List<String> roleIds = userRoleList.stream().map(UserRole::getRoleId).collect(Collectors.toList());
|
||||||
|
|
||||||
|
@ -117,9 +125,9 @@ public class UserService {
|
||||||
roleExample.createCriteria().andIdIn(roleIds);
|
roleExample.createCriteria().andIdIn(roleIds);
|
||||||
|
|
||||||
List<Role> roleList = roleMapper.selectByExample(roleExample);
|
List<Role> roleList = roleMapper.selectByExample(roleExample);
|
||||||
userDTO.setRoles(roleList);
|
userRoleDTO.setRoles(roleList);
|
||||||
|
|
||||||
return userDTO;
|
return userRoleDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<User> getUserList() {
|
public List<User> getUserList() {
|
||||||
|
|
|
@ -77,7 +77,7 @@ public class TestCaseController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/import/{projectId}")
|
@PostMapping("/import/{projectId}")
|
||||||
public ExcelResponse testCaseImport(MultipartFile file, @PathVariable String projectId){
|
public ExcelResponse testCaseImport(MultipartFile file, @PathVariable String projectId) throws NoSuchFieldException {
|
||||||
return testCaseService.testCaseImport(file, projectId);
|
return testCaseService.testCaseImport(file, projectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,14 +9,13 @@ import io.metersphere.base.mapper.ext.ExtTestCaseMapper;
|
||||||
import io.metersphere.commons.exception.MSException;
|
import io.metersphere.commons.exception.MSException;
|
||||||
import io.metersphere.commons.user.SessionUser;
|
import io.metersphere.commons.user.SessionUser;
|
||||||
import io.metersphere.commons.utils.BeanUtils;
|
import io.metersphere.commons.utils.BeanUtils;
|
||||||
import io.metersphere.commons.utils.LogUtil;
|
|
||||||
import io.metersphere.commons.utils.SessionUtils;
|
import io.metersphere.commons.utils.SessionUtils;
|
||||||
import io.metersphere.excel.domain.ExcelErrData;
|
import io.metersphere.excel.domain.ExcelErrData;
|
||||||
import io.metersphere.excel.domain.ExcelResponse;
|
import io.metersphere.excel.domain.ExcelResponse;
|
||||||
import io.metersphere.excel.domain.TestCaseExcelData;
|
import io.metersphere.excel.domain.TestCaseExcelData;
|
||||||
import io.metersphere.excel.listener.EasyExcelListener;
|
import io.metersphere.excel.listener.EasyExcelListener;
|
||||||
import io.metersphere.excel.listener.TestCaseDataListener;
|
import io.metersphere.excel.listener.TestCaseDataListener;
|
||||||
import io.metersphere.excel.utils.EasyExcelUtil;
|
import io.metersphere.excel.utils.EasyExcelExporter;
|
||||||
import io.metersphere.i18n.Translator;
|
import io.metersphere.i18n.Translator;
|
||||||
import io.metersphere.track.dto.TestCaseDTO;
|
import io.metersphere.track.dto.TestCaseDTO;
|
||||||
import io.metersphere.track.request.testcase.QueryTestCaseRequest;
|
import io.metersphere.track.request.testcase.QueryTestCaseRequest;
|
||||||
|
@ -31,7 +30,6 @@ import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -60,9 +58,6 @@ public class TestCaseService {
|
||||||
@Resource
|
@Resource
|
||||||
TestCaseNodeService testCaseNodeService;
|
TestCaseNodeService testCaseNodeService;
|
||||||
|
|
||||||
@Resource
|
|
||||||
TestCaseDataListener testCaseDataListener;
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
UserMapper userMapper;
|
UserMapper userMapper;
|
||||||
|
|
||||||
|
@ -173,8 +168,6 @@ public class TestCaseService {
|
||||||
|
|
||||||
public ExcelResponse testCaseImport(MultipartFile file, String projectId) {
|
public ExcelResponse testCaseImport(MultipartFile file, String projectId) {
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
ExcelResponse excelResponse = new ExcelResponse();
|
ExcelResponse excelResponse = new ExcelResponse();
|
||||||
|
|
||||||
String currentWorkspaceId = SessionUtils.getCurrentWorkspaceId();
|
String currentWorkspaceId = SessionUtils.getCurrentWorkspaceId();
|
||||||
|
@ -190,10 +183,17 @@ public class TestCaseService {
|
||||||
List<User> users = userMapper.selectByExample(userExample);
|
List<User> users = userMapper.selectByExample(userExample);
|
||||||
Set<String> userIds = users.stream().map(User::getId).collect(Collectors.toSet());
|
Set<String> userIds = users.stream().map(User::getId).collect(Collectors.toSet());
|
||||||
|
|
||||||
EasyExcelFactory.read(file.getInputStream(), TestCaseExcelData.class,
|
EasyExcelListener easyExcelListener = null;
|
||||||
testCaseDataListener.init(projectId, testCaseNames, userIds)).sheet().doRead();
|
List<ExcelErrData<TestCaseExcelData>> errList = null;
|
||||||
|
try {
|
||||||
List<ExcelErrData<TestCaseExcelData>> errList = testCaseDataListener.getAndClearErrList();
|
easyExcelListener = new TestCaseDataListener(this, projectId, testCaseNames, userIds);
|
||||||
|
EasyExcelFactory.read(file.getInputStream(), TestCaseExcelData.class, easyExcelListener).sheet().doRead();
|
||||||
|
errList = easyExcelListener.getErrList();
|
||||||
|
} catch (Exception e) {
|
||||||
|
MSException.throwException(e.getMessage());
|
||||||
|
} finally {
|
||||||
|
easyExcelListener.close();
|
||||||
|
}
|
||||||
//如果包含错误信息就导出错误信息
|
//如果包含错误信息就导出错误信息
|
||||||
if (!errList.isEmpty()) {
|
if (!errList.isEmpty()) {
|
||||||
excelResponse.setSuccess(false);
|
excelResponse.setSuccess(false);
|
||||||
|
@ -202,13 +202,6 @@ public class TestCaseService {
|
||||||
excelResponse.setSuccess(true);
|
excelResponse.setSuccess(true);
|
||||||
}
|
}
|
||||||
return excelResponse;
|
return excelResponse;
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveImportData(List<TestCaseWithBLOBs> testCases, String projectId) {
|
public void saveImportData(List<TestCaseWithBLOBs> testCases, String projectId) {
|
||||||
|
@ -226,8 +219,16 @@ public class TestCaseService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCaseTemplateExport(HttpServletResponse response) {
|
public void testCaseTemplateExport(HttpServletResponse response) {
|
||||||
EasyExcelUtil.export(response, TestCaseExcelData.class, generateExportTemplate(),
|
EasyExcelExporter easyExcelExporter = null;
|
||||||
|
try {
|
||||||
|
easyExcelExporter = new EasyExcelExporter();
|
||||||
|
easyExcelExporter.export(response, TestCaseExcelData.class, generateExportTemplate(),
|
||||||
Translator.get("test_case_import_template_name"), Translator.get("test_case_import_template_sheet"));
|
Translator.get("test_case_import_template_name"), Translator.get("test_case_import_template_sheet"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
MSException.throwException(e);
|
||||||
|
} finally {
|
||||||
|
easyExcelExporter.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<TestCaseExcelData> generateExportTemplate() {
|
private List<TestCaseExcelData> generateExportTemplate() {
|
||||||
|
@ -238,28 +239,29 @@ public class TestCaseService {
|
||||||
SessionUser user = SessionUtils.getUser();
|
SessionUser user = SessionUtils.getUser();
|
||||||
for (int i = 1; i <= 5; i++) {
|
for (int i = 1; i <= 5; i++) {
|
||||||
TestCaseExcelData data = new TestCaseExcelData();
|
TestCaseExcelData data = new TestCaseExcelData();
|
||||||
data.setName("测试用例" + i);
|
data.setName(Translator.get("test_case") + i);
|
||||||
path.append("/" + "模块" + i);
|
path.append("/" + Translator.get("module") + i);
|
||||||
data.setNodePath(path.toString());
|
data.setNodePath(path.toString());
|
||||||
data.setPriority("P" + i%4);
|
data.setPriority("P" + i%4);
|
||||||
data.setType(types.get(i%3));
|
data.setType(types.get(i%3));
|
||||||
data.setMethod(methods.get(i%2));
|
data.setMethod(methods.get(i%2));
|
||||||
data.setPrerequisite("前置条件选填");
|
data.setPrerequisite(Translator.get("preconditions_optional"));
|
||||||
data.setStepDesc("1. 每个步骤以换行分隔\n2. 步骤前可标序号\n3. 测试步骤和结果选填");
|
data.setStepDesc("1. " + Translator.get("step_tip_separate") +
|
||||||
data.setStepResult("1. 每条结果以换行分隔\n2. 结果前可标序号\n3. 测试步骤和结果选填");
|
"\n2. " + Translator.get("step_tip_order") + "\n3. " + Translator.get("step_tip_optional"));
|
||||||
|
data.setStepResult("1. " + Translator.get("step_tip_order") + "\n2. " + Translator.get("result_tip_order") + "\n3. " + Translator.get("result_tip_optional"));
|
||||||
data.setMaintainer(user.getId());
|
data.setMaintainer(user.getId());
|
||||||
data.setRemark("备注选填");
|
data.setRemark(Translator.get("remark_optional"));
|
||||||
list.add(data);
|
list.add(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
list.add(new TestCaseExcelData());
|
list.add(new TestCaseExcelData());
|
||||||
TestCaseExcelData explain = new TestCaseExcelData();
|
TestCaseExcelData explain = new TestCaseExcelData();
|
||||||
explain.setName("同一项目下测试用例名称不能重复!");
|
explain.setName(Translator.get("do_not_modify_header_order"));
|
||||||
explain.setNodePath("模块名称请按照'/模块1/模块2'的格式书写; 错误格式示例:('/', '/tes//test'); 若无该模块,则自动创建模块");
|
explain.setNodePath(Translator.get("module_created_automatically"));
|
||||||
explain.setType("用例类型必须为:functional、performance、api");
|
explain.setType(Translator.get("options") + "(functional、performance、api)");
|
||||||
explain.setMethod("测试方式必须为:manual、auto");
|
explain.setMethod(Translator.get("options") + "(manual、auto)");
|
||||||
explain.setPriority("优先级必须为:P0、P1、P2、P3");
|
explain.setPriority(Translator.get("options") + "(P0、P1、P2、P3)");
|
||||||
explain.setMaintainer("维护人必须为该工作空间相关人员");
|
explain.setMaintainer(Translator.get("please_input_workspace_member"));
|
||||||
|
|
||||||
list.add(explain);
|
list.add(explain);
|
||||||
return list;
|
return list;
|
||||||
|
|
|
@ -18,3 +18,27 @@ incorrect_format=
|
||||||
test_case_type_validate=
|
test_case_type_validate=
|
||||||
test_case_priority_validate=
|
test_case_priority_validate=
|
||||||
test_case_method_validate=
|
test_case_method_validate=
|
||||||
|
test_case_name=
|
||||||
|
test_case_module=
|
||||||
|
test_case_type=
|
||||||
|
test_case_maintainer=
|
||||||
|
test_case_priority=
|
||||||
|
test_case_method=
|
||||||
|
test_case_prerequisite=
|
||||||
|
test_case_remark=
|
||||||
|
test_case_step_desc=
|
||||||
|
test_case_step_result=
|
||||||
|
test_case=
|
||||||
|
module=
|
||||||
|
preconditions_optional=
|
||||||
|
step_tip_separate=
|
||||||
|
step_tip_order=
|
||||||
|
step_tip_optional=
|
||||||
|
result_tip_separate=
|
||||||
|
result_tip_order=
|
||||||
|
result_tip_optional=
|
||||||
|
remark_optional=
|
||||||
|
do_not_modify_header_order=
|
||||||
|
module_created_automatically=
|
||||||
|
options=
|
||||||
|
please_input_workspace_member=
|
|
@ -59,3 +59,26 @@ incorrect_format=Incorrect format
|
||||||
test_case_type_validate=must be functional, performance, api
|
test_case_type_validate=must be functional, performance, api
|
||||||
test_case_priority_validate=must be P0, P1, P2, P3
|
test_case_priority_validate=must be P0, P1, P2, P3
|
||||||
test_case_method_validate=\ must be manual, auto
|
test_case_method_validate=\ must be manual, auto
|
||||||
|
test_case_name=Name
|
||||||
|
test_case_type=Type
|
||||||
|
test_case_priority=Priority
|
||||||
|
test_case_method=method
|
||||||
|
test_case_prerequisite=Prerequisite
|
||||||
|
test_case_remark=Remark
|
||||||
|
test_case_step_desc=Step description
|
||||||
|
test_case_step_result=Step result
|
||||||
|
test_case_module=module
|
||||||
|
test_case=Test case
|
||||||
|
module=Module
|
||||||
|
preconditions_optional=Preconditions optional
|
||||||
|
step_tip_separate=Each step is separated by a new line
|
||||||
|
step_tip_order=The serial number can be marked before the step
|
||||||
|
step_tip_optional=Test steps and results optional
|
||||||
|
result_tip_separate=Each result is separated by a new line
|
||||||
|
result_tip_order=The sequence number can be marked before the result
|
||||||
|
result_tip_optional=Test steps and results optional
|
||||||
|
remark_optional=Remark optional
|
||||||
|
do_not_modify_header_order=Do not modify the header order
|
||||||
|
module_created_automatically=If there is no such module, will be created automatically
|
||||||
|
options=options
|
||||||
|
please_input_workspace_member=Please input workspace merber
|
|
@ -51,11 +51,35 @@ parse_data_error=解析数据出错
|
||||||
missing_header_information=缺少头部信息
|
missing_header_information=缺少头部信息
|
||||||
number=第
|
number=第
|
||||||
row=行
|
row=行
|
||||||
incorrect_format=格式不正确
|
incorrect_format=所属模块
|
||||||
test_case_type_validate=必须为functional、performance、api
|
test_case_type_validate=必须为functional、performance、api
|
||||||
test_case_priority_validate=必须为P0、P1、P2、P3
|
test_case_priority_validate=必须为P0、P1、P2、P3
|
||||||
test_case_method_validate=必须为manual、auto
|
test_case_method_validate=必须为manual、auto
|
||||||
error=出错
|
error=出错
|
||||||
|
test_case_name=用例名称
|
||||||
|
test_case_type=用例类型
|
||||||
|
test_case_maintainer=维护人
|
||||||
|
test_case_priority=优先级
|
||||||
|
test_case_method=测试方式
|
||||||
|
test_case_prerequisite=前置条件
|
||||||
|
test_case_remark=备注
|
||||||
|
test_case_step_desc=步骤描述
|
||||||
|
test_case_step_result=预期结果
|
||||||
|
test_case_module=所属模块
|
||||||
|
test_case=测试用例
|
||||||
|
module=模块
|
||||||
|
preconditions_optional=前置条件选填
|
||||||
|
step_tip_separate=每个步骤以换行分隔
|
||||||
|
step_tip_order=步骤前可标序号
|
||||||
|
step_tip_optional=步骤前可标序号
|
||||||
|
result_tip_separate=每条结果以换行分隔
|
||||||
|
result_tip_order=结果前可标序号
|
||||||
|
result_tip_optional=测试步骤和结果选填
|
||||||
|
remark_optional=备注选填
|
||||||
|
do_not_modify_header_order=请勿修改表头顺序
|
||||||
|
module_created_automatically=若无该模块将自动创建
|
||||||
|
options=选项
|
||||||
|
please_input_workspace_member=请填写该工作空间相关人员
|
||||||
test_case_exist=该项目下已存在用例:
|
test_case_exist=该项目下已存在用例:
|
||||||
node_deep_limit=节点深度不超过5层!
|
node_deep_limit=节点深度不超过5层!
|
||||||
before_delete_plan=该计划下存在关联测试用例,请先取消关联!
|
before_delete_plan=该计划下存在关联测试用例,请先取消关联!
|
||||||
|
|
|
@ -51,11 +51,35 @@ parse_data_error=解析數據出錯
|
||||||
missing_header_information=缺少頭部信息
|
missing_header_information=缺少頭部信息
|
||||||
number=第
|
number=第
|
||||||
row=行
|
row=行
|
||||||
incorrect_format=格式不正確
|
incorrect_format=所屬模塊
|
||||||
test_case_type_validate=必須為functional、performance、api
|
test_case_type_validate=必須為functional、performance、api
|
||||||
test_case_priority_validate=必須為P0、P1、P2、P3
|
test_case_priority_validate=必須為P0、P1、P2、P3
|
||||||
test_case_method_validate=必須為manual、auto
|
test_case_method_validate=必須為manual、auto
|
||||||
error=出错
|
error=出錯
|
||||||
|
test_case_name=用例名稱
|
||||||
|
test_case_type=用例類型
|
||||||
|
test_case_maintainer=維護人
|
||||||
|
test_case_priority=優先級
|
||||||
|
test_case_method=測試方式
|
||||||
|
test_case_prerequisite=前置條件
|
||||||
|
test_case_remark=備註
|
||||||
|
test_case_step_desc=步驟描述
|
||||||
|
test_case_step_result=預期結果
|
||||||
|
test_case_module=所屬模塊
|
||||||
|
test_case=測試用例
|
||||||
|
module=模塊
|
||||||
|
preconditions_optional=前置條件選填
|
||||||
|
step_tip_separate=每個步驟以換行分隔
|
||||||
|
step_tip_order=步驟前可標序號
|
||||||
|
step_tip_optional=步驟前可標序號
|
||||||
|
result_tip_separate=每條結果以換行分隔
|
||||||
|
result_tip_order=結果前可標序號
|
||||||
|
result_tip_optional=測試步驟和結果選填
|
||||||
|
remark_optional=備註選填
|
||||||
|
do_not_modify_header_order=請勿修改表頭順序
|
||||||
|
module_created_automatically=若無該模塊將自動創建
|
||||||
|
options=選項
|
||||||
|
please_input_workspace_member=請填寫該工作空間相關人員
|
||||||
test_case_exist=該項目下已存在用例:
|
test_case_exist=該項目下已存在用例:
|
||||||
node_deep_limit=節點深度不超過5層!
|
node_deep_limit=節點深度不超過5層!
|
||||||
before_delete_plan=該計劃下存在關聯測試用例,請先取消關聯!
|
before_delete_plan=該計劃下存在關聯測試用例,請先取消關聯!
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
|
|
||||||
<!--Change personal password-->
|
<!--Change personal password-->
|
||||||
<el-dialog :title="$t('member.edit_password')" :visible.sync="editPasswordVisible" width="30%" left>
|
<el-dialog :title="$t('member.edit_password')" :visible.sync="editPasswordVisible" width="30%" left>
|
||||||
<el-form :model="ruleForm" :rules="rules" ref="editPasswordForm" label-width="100px" class="demo-ruleForm">
|
<el-form :model="ruleForm" :rules="rules" ref="editPasswordForm" label-width="120px" class="demo-ruleForm">
|
||||||
<el-form-item :label="$t('member.old_password')" prop="password">
|
<el-form-item :label="$t('member.old_password')" prop="password">
|
||||||
<el-input v-model="ruleForm.password" autocomplete="off" show-password/>
|
<el-input v-model="ruleForm.password" autocomplete="off" show-password/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
|
@ -9,9 +9,13 @@
|
||||||
|
|
||||||
<el-table :data="tableData" style="width: 100%">
|
<el-table :data="tableData" style="width: 100%">
|
||||||
<el-table-column prop="id" label="ID"/>
|
<el-table-column prop="id" label="ID"/>
|
||||||
<el-table-column prop="name" :label="$t('commons.username')"/>
|
<el-table-column prop="name" :label="$t('commons.username')" width="200"/>
|
||||||
|
<el-table-column :label="$t('commons.role')" width="120">
|
||||||
|
<template v-slot:default="scope">
|
||||||
|
<ms-roles-tag :roles="scope.row.roles"/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="email" :label="$t('commons.email')"/>
|
<el-table-column prop="email" :label="$t('commons.email')"/>
|
||||||
<el-table-column prop="phone" :label="$t('commons.phone')"/>
|
|
||||||
<el-table-column prop="status" :label="$t('commons.status')">
|
<el-table-column prop="status" :label="$t('commons.status')">
|
||||||
<template v-slot:default="scope">
|
<template v-slot:default="scope">
|
||||||
<el-switch v-model="scope.row.status"
|
<el-switch v-model="scope.row.status"
|
||||||
|
@ -23,7 +27,7 @@
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="createTime" :label="$t('commons.create_time')" width="180">
|
<el-table-column prop="createTime" :label="$t('commons.create_time')">
|
||||||
<template v-slot:default="scope">
|
<template v-slot:default="scope">
|
||||||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
@ -34,8 +38,6 @@
|
||||||
<template v-slot:behind>
|
<template v-slot:behind>
|
||||||
<ms-table-operator-button :tip="$t('member.edit_password')" icon="el-icon-s-tools"
|
<ms-table-operator-button :tip="$t('member.edit_password')" icon="el-icon-s-tools"
|
||||||
type="success" @exec="editPassword(scope.row)"/>
|
type="success" @exec="editPassword(scope.row)"/>
|
||||||
<ms-table-operator-button :tip="$t('commons.set_admin')" icon="el-icon-user-solid"
|
|
||||||
type="danger" @exec="openCheckDialog(scope.row)"/>
|
|
||||||
</template>
|
</template>
|
||||||
</ms-table-operator>
|
</ms-table-operator>
|
||||||
</template>
|
</template>
|
||||||
|
@ -46,21 +48,6 @@
|
||||||
:total="total"/>
|
:total="total"/>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-dialog :title="$t('commons.verification')" :visible.sync="checkPasswordVisible" width="30%"
|
|
||||||
@close="closeCheckPassword" :destroy-on-close="true">
|
|
||||||
<el-form :model="checkPasswordForm" label-position="right" label-width="100px" size="small" :rules="rule"
|
|
||||||
ref="checkPasswordForm">
|
|
||||||
<el-form-item :label="$t('commons.password')" prop="password">
|
|
||||||
<el-input type="password" v-model="checkPasswordForm.password" autocomplete="off" show-password></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<template v-slot:footer>
|
|
||||||
<ms-dialog-footer
|
|
||||||
@cancel="checkPasswordVisible = false"
|
|
||||||
@confirm="setAdmin('checkPasswordForm')"/>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
|
|
||||||
<!--Create user-->
|
<!--Create user-->
|
||||||
<el-dialog :title="$t('user.create')" :visible.sync="createVisible" width="30%" @closed="handleClose"
|
<el-dialog :title="$t('user.create')" :visible.sync="createVisible" width="30%" @closed="handleClose"
|
||||||
:destroy-on-close="true">
|
:destroy-on-close="true">
|
||||||
|
@ -113,12 +100,12 @@
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<!--Changing user password in system settings-->
|
<!--Changing user password in system settings-->
|
||||||
<el-dialog :title="$t('member.edit_password')" :visible.sync="editPasswordVisible" width="30%" left>
|
<el-dialog :title="$t('member.edit_password')" :visible.sync="editPasswordVisible" width="30%" left>
|
||||||
<el-form :model="ruleForm" label-position="right" label-width="100px" size="small" :rules="rule"
|
<el-form :model="ruleForm" label-position="right" label-width="120px" size="small" :rules="rule"
|
||||||
ref="editPasswordForm" class="demo-ruleForm">
|
ref="editPasswordForm" class="demo-ruleForm">
|
||||||
<el-form-item :label="$t('member.new_password')" prop="newpassword">
|
<el-form-item :label="$t('member.new_password')" prop="newpassword">
|
||||||
<el-input type="password" v-model="ruleForm.newpassword" autocomplete="off" show-password></el-input>
|
<el-input type="password" v-model="ruleForm.newpassword" autocomplete="off" show-password></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item >
|
<el-form-item>
|
||||||
<el-input v-model="ruleForm.id" autocomplete="off" :disabled="true" style="display:none"/>
|
<el-input v-model="ruleForm.id" autocomplete="off" :disabled="true" style="display:none"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
@ -140,10 +127,19 @@
|
||||||
import MsDialogFooter from "../../common/components/MsDialogFooter";
|
import MsDialogFooter from "../../common/components/MsDialogFooter";
|
||||||
import MsTableOperatorButton from "../../common/components/MsTableOperatorButton";
|
import MsTableOperatorButton from "../../common/components/MsTableOperatorButton";
|
||||||
import {getCurrentUser} from "../../../../common/js/utils";
|
import {getCurrentUser} from "../../../../common/js/utils";
|
||||||
|
import MsRolesTag from "../../common/components/MsRolesTag";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsUser",
|
name: "MsUser",
|
||||||
components: {MsCreateBox, MsTablePagination, MsTableHeader, MsTableOperator, MsDialogFooter, MsTableOperatorButton},
|
components: {
|
||||||
|
MsCreateBox,
|
||||||
|
MsTablePagination,
|
||||||
|
MsTableHeader,
|
||||||
|
MsTableOperator,
|
||||||
|
MsDialogFooter,
|
||||||
|
MsTableOperatorButton,
|
||||||
|
MsRolesTag
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
queryPath: '/user/special/list',
|
queryPath: '/user/special/list',
|
||||||
|
@ -155,7 +151,6 @@
|
||||||
createVisible: false,
|
createVisible: false,
|
||||||
updateVisible: false,
|
updateVisible: false,
|
||||||
editPasswordVisible: false,
|
editPasswordVisible: false,
|
||||||
checkPasswordVisible: false,
|
|
||||||
multipleSelection: [],
|
multipleSelection: [],
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
pageSize: 5,
|
pageSize: 5,
|
||||||
|
@ -274,9 +269,9 @@
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
editUserPassword(editPasswordForm){
|
editUserPassword(editPasswordForm) {
|
||||||
this.$refs[editPasswordForm].validate(valid=>{
|
this.$refs[editPasswordForm].validate(valid => {
|
||||||
if(valid){
|
if (valid) {
|
||||||
this.result = this.$post(this.editPasswordPath, this.ruleForm, response => {
|
this.result = this.$post(this.editPasswordPath, this.ruleForm, response => {
|
||||||
this.$success(this.$t('commons.modify_success'));
|
this.$success(this.$t('commons.modify_success'));
|
||||||
this.editPasswordVisible = false;
|
this.editPasswordVisible = false;
|
||||||
|
@ -293,6 +288,15 @@
|
||||||
let data = response.data;
|
let data = response.data;
|
||||||
this.total = data.itemCount;
|
this.total = data.itemCount;
|
||||||
this.tableData = data.listObject;
|
this.tableData = data.listObject;
|
||||||
|
let url = "/user/special/user/role";
|
||||||
|
for (let i = 0; i < this.tableData.length; i++) {
|
||||||
|
this.$get(url + '/' + this.tableData[i].id, result => {
|
||||||
|
let data = result.data;
|
||||||
|
let roles = data.roles;
|
||||||
|
// let userRoles = result.userRoles;
|
||||||
|
this.$set(this.tableData[i], "roles", roles);
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
handleClose() {
|
handleClose() {
|
||||||
|
@ -308,28 +312,6 @@
|
||||||
},
|
},
|
||||||
handleSelectionChange(val) {
|
handleSelectionChange(val) {
|
||||||
this.multipleSelection = val;
|
this.multipleSelection = val;
|
||||||
},
|
|
||||||
closeCheckPassword() {
|
|
||||||
this.checkPasswordForm = {};
|
|
||||||
},
|
|
||||||
openCheckDialog(row) {
|
|
||||||
this.$set(this.setAdminParam, 'id', row.id);
|
|
||||||
this.checkPasswordVisible = true;
|
|
||||||
},
|
|
||||||
setAdmin(checkPasswordForm) {
|
|
||||||
let user = getCurrentUser();
|
|
||||||
this.$set(this.setAdminParam, 'adminId', user.id);
|
|
||||||
this.$set(this.setAdminParam, 'password', this.checkPasswordForm.password);
|
|
||||||
this.$refs[checkPasswordForm].validate(valid => {
|
|
||||||
if (valid) {
|
|
||||||
this.$post("/user/set/admin", this.setAdminParam, () => {
|
|
||||||
this.$success(this.$t('commons.modify_success'));
|
|
||||||
this.checkPasswordVisible = false;
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,6 @@ export default {
|
||||||
'personal_information': 'Personal Information',
|
'personal_information': 'Personal Information',
|
||||||
'exit_system': 'Exit System',
|
'exit_system': 'Exit System',
|
||||||
'verification': 'Verification',
|
'verification': 'Verification',
|
||||||
'set_admin': 'Set Admin',
|
|
||||||
'title': 'Title',
|
'title': 'Title',
|
||||||
'custom': 'Custom',
|
'custom': 'Custom',
|
||||||
'select_date': 'Select date',
|
'select_date': 'Select date',
|
||||||
|
@ -124,8 +123,8 @@ export default {
|
||||||
'please_choose_member': 'Please Choose Member',
|
'please_choose_member': 'Please Choose Member',
|
||||||
'search_by_name': 'Search by name',
|
'search_by_name': 'Search by name',
|
||||||
'modify_personal_info': 'Modify Personal Information',
|
'modify_personal_info': 'Modify Personal Information',
|
||||||
'edit_password': 'Edit_Password',
|
'edit_password': 'Edit Password',
|
||||||
'edit_information': 'Edit_Information',
|
'edit_information': 'Edit Information',
|
||||||
'input_name': 'Please enter a user name',
|
'input_name': 'Please enter a user name',
|
||||||
'input_email': 'Please enter a email',
|
'input_email': 'Please enter a email',
|
||||||
'special_characters_are_not_supported': 'Special characters are not supported',
|
'special_characters_are_not_supported': 'Special characters are not supported',
|
||||||
|
|
|
@ -56,7 +56,6 @@ export default {
|
||||||
'personal_information': '个人信息',
|
'personal_information': '个人信息',
|
||||||
'exit_system': '退出系统',
|
'exit_system': '退出系统',
|
||||||
'verification': '验证',
|
'verification': '验证',
|
||||||
'set_admin': '设置为管理员',
|
|
||||||
'title': '标题',
|
'title': '标题',
|
||||||
'custom': '自定义',
|
'custom': '自定义',
|
||||||
'select_date': '选择日期',
|
'select_date': '选择日期',
|
||||||
|
|
|
@ -56,7 +56,6 @@ export default {
|
||||||
'personal_information': '個人信息',
|
'personal_information': '個人信息',
|
||||||
'exit_system': '退出系統',
|
'exit_system': '退出系統',
|
||||||
'verification': '驗證',
|
'verification': '驗證',
|
||||||
'set_admin': '設置為管理員',
|
|
||||||
'title': '標題',
|
'title': '標題',
|
||||||
'custom': '自定義',
|
'custom': '自定義',
|
||||||
'select_date': '選擇日期',
|
'select_date': '選擇日期',
|
||||||
|
|
Loading…
Reference in New Issue