This commit is contained in:
fit2-zhao 2020-11-30 11:03:04 +08:00
commit c5380e6934
104 changed files with 768 additions and 370 deletions

View File

@ -4,7 +4,7 @@ MAINTAINER FIT2CLOUD <support@fit2cloud.com>
ARG MS_VERSION=dev ARG MS_VERSION=dev
RUN mkdir -p /opt/apps && mkdir -p /opt/jmeter RUN mkdir -p /opt/apps && mkdir -p /opt/jmeter/lib/junit
COPY backend/target/backend-1.5.jar /opt/apps COPY backend/target/backend-1.5.jar /opt/apps

View File

@ -21,4 +21,5 @@ public class Scenario {
private TCPConfig tcpConfig; private TCPConfig tcpConfig;
private List<DatabaseConfig> databaseConfigs; private List<DatabaseConfig> databaseConfigs;
private Boolean enable; private Boolean enable;
private Boolean referenceEnable;
} }

View File

@ -107,7 +107,12 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
ScenarioResult scenarioResult; ScenarioResult scenarioResult;
if (!scenarios.containsKey(scenarioId)) { if (!scenarios.containsKey(scenarioId)) {
scenarioResult = new ScenarioResult(); scenarioResult = new ScenarioResult();
scenarioResult.setId(scenarioId); try {
scenarioResult.setId(Integer.parseInt(scenarioId));
} catch (Exception e) {
scenarioResult.setId(0);
LogUtil.error("场景ID转换异常: " + e.getMessage());
}
scenarioResult.setName(scenarioName); scenarioResult.setName(scenarioName);
scenarios.put(scenarioId, scenarioResult); scenarios.put(scenarioId, scenarioResult);
} else { } else {
@ -156,13 +161,13 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
testPlanTestCaseService.updateTestCaseStates(ids, TestPlanTestCaseStatus.Failure.name()); testPlanTestCaseService.updateTestCaseStates(ids, TestPlanTestCaseStatus.Failure.name());
} }
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
try { try {
sendTask(report, testResult); sendTask(report, testResult);
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }

View File

@ -8,7 +8,7 @@ import java.util.List;
@Data @Data
public class ScenarioResult { public class ScenarioResult {
private String id; private Integer id;
private String name; private String name;

View File

@ -50,7 +50,7 @@ public class JmeterDocumentParser {
} }
return documentToBytes(document); return documentToBytes(document);
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
return source; return source;
} }
} }
@ -161,7 +161,9 @@ public class JmeterDocumentParser {
break; break;
case "Argument.value": case "Argument.value":
String textContent = ele.getTextContent(); String textContent = ele.getTextContent();
if (StringUtils.startsWith(textContent, "@")) {
ele.setTextContent(ScriptEngineUtils.calculate(textContent)); ele.setTextContent(ScriptEngineUtils.calculate(textContent));
}
break; break;
default: default:
break; break;

View File

@ -25,7 +25,10 @@ import io.metersphere.i18n.Translator;
import io.metersphere.job.sechedule.ApiTestJob; import io.metersphere.job.sechedule.ApiTestJob;
import io.metersphere.notice.service.MailService; import io.metersphere.notice.service.MailService;
import io.metersphere.notice.service.NoticeService; import io.metersphere.notice.service.NoticeService;
import io.metersphere.service.*; import io.metersphere.service.FileService;
import io.metersphere.service.QuotaService;
import io.metersphere.service.ScheduleService;
import io.metersphere.service.UserService;
import io.metersphere.track.service.TestCaseService; import io.metersphere.track.service.TestCaseService;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants; import org.apache.dubbo.common.constants.CommonConstants;
@ -66,6 +69,7 @@ public class APITestService {
@Resource @Resource
private NoticeService noticeService; private NoticeService noticeService;
private static final String BODY_FILE_DIR = "/opt/metersphere/data/body"; private static final String BODY_FILE_DIR = "/opt/metersphere/data/body";
public List<APITestResult> list(QueryAPITestRequest request) { public List<APITestResult> list(QueryAPITestRequest request) {
@ -127,7 +131,7 @@ public class APITestService {
file.createNewFile(); file.createNewFile();
FileUtil.copyStream(in, out); FileUtil.copyStream(in, out);
} catch (IOException e) { } catch (IOException e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
MSException.throwException(Translator.get("upload_fail")); MSException.throwException(Translator.get("upload_fail"));
} }
} }
@ -170,7 +174,7 @@ public class APITestService {
try { try {
FileUtil.copyDir(sourceFile, new File(targetDir)); FileUtil.copyDir(sourceFile, new File(targetDir));
} catch (IOException e) { } catch (IOException e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
MSException.throwException(Translator.get("upload_fail")); MSException.throwException(Translator.get("upload_fail"));
} }
} }
@ -433,7 +437,7 @@ public class APITestService {
bytes = JmeterDocumentParser.parse(bytes); bytes = JmeterDocumentParser.parse(bytes);
is = new ByteArrayInputStream(bytes); is = new ByteArrayInputStream(bytes);
} catch (IOException e) { } catch (IOException e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
jMeterService.run(request.getId(), reportId, is); jMeterService.run(request.getId(), reportId, is);

View File

@ -133,6 +133,7 @@
LEFT JOIN user ON user.id = r.user_id LEFT JOIN user ON user.id = r.user_id
<where> <where>
r.test_id = #{testId} r.test_id = #{testId}
and r.status != 'Debug'
</where> </where>
ORDER BY r.update_time DESC ORDER BY r.update_time DESC
</select> </select>

View File

@ -38,4 +38,5 @@ public interface ExtTestPlanTestCaseMapper {
*/ */
List<TestPlanCaseDTO> listTestCaseByProjectIds(@Param("ids") List<String> ids); List<TestPlanCaseDTO> listTestCaseByProjectIds(@Param("ids") List<String> ids);
TestPlanCaseDTO get(String testPlanTestCaseId);
} }

View File

@ -307,6 +307,16 @@
</if> </if>
</where> </where>
</select> </select>
<select id="get" resultType="io.metersphere.track.dto.TestPlanCaseDTO">
select test_case.remark, test_plan_test_case.id as id, test_plan_test_case.*,test_case.*,test_case_node.name as model, project.name as projectName
from test_plan_test_case
inner join test_case on test_plan_test_case.case_id = test_case.id
left join test_case_node on test_case_node.id=test_case.node_id
inner join project on project.id = test_case.project_id
where test_plan_test_case.id = #{testPlanTestCaseId}
</select>
<update id="updateTestCaseStates" parameterType="java.lang.String"> <update id="updateTestCaseStates" parameterType="java.lang.String">
update test_plan_test_case update test_plan_test_case
<set> <set>

View File

@ -9,4 +9,5 @@ import java.util.List;
public interface ExtWorkspaceMapper { public interface ExtWorkspaceMapper {
List<WorkspaceDTO> getWorkspaceWithOrg(@Param("request") WorkspaceRequest request); List<WorkspaceDTO> getWorkspaceWithOrg(@Param("request") WorkspaceRequest request);
List<String> getWorkspaceIdsByOrgId(@Param("orgId") String orgId);
} }

View File

@ -13,4 +13,9 @@
order by w.update_time desc order by w.update_time desc
</select> </select>
<select id="getWorkspaceIdsByOrgId" resultType="java.lang.String">
select id from workspace
where organization_id = #{orgId}
</select>
</mapper> </mapper>

View File

@ -88,7 +88,7 @@ public class CompressUtils {
gzip.finish(); gzip.finish();
return obj.toByteArray(); return obj.toByteArray();
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
return data; return data;
} }
} }
@ -116,7 +116,7 @@ public class CompressUtils {
baos.flush(); baos.flush();
return baos.toByteArray(); return baos.toByteArray();
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
return data; return data;
} }
} }

View File

@ -12,6 +12,7 @@ import java.util.stream.Collectors;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath; import com.alibaba.fastjson.JSONPath;
import org.apache.commons.lang3.StringUtils;
public class JsonPathUtils { public class JsonPathUtils {
@ -47,10 +48,6 @@ public class JsonPathUtils {
String o_json_path = "$" + jsonPath.next().replaceAll("/", "."); String o_json_path = "$" + jsonPath.next().replaceAll("/", ".");
String value = JSONPath.eval(jsonObject, o_json_path).toString(); String value = JSONPath.eval(jsonObject, o_json_path).toString();
if(o_json_path.toLowerCase().contains("id")) {
continue;
}
if(value.equals("") || value.equals("[]") || o_json_path.equals("")) { if(value.equals("") || value.equals("[]") || o_json_path.equals("")) {
continue; continue;
} }
@ -68,9 +65,26 @@ public class JsonPathUtils {
.compareTo( (String)b.get("json_path") ) .compareTo( (String)b.get("json_path") )
); );
// 正则特殊字符转义
allJsons.forEach(item -> {
item.put("regular_expression", escapeExprSpecialWord((String) item.get("json_value")));
});
return allJsons; return allJsons;
} }
public static String escapeExprSpecialWord(String keyword) {
if (StringUtils.isNotBlank(keyword)) {
String[] fbsArr = {"\\", "$", "(", ")", "*", "+", ".", "[", "]", "?", "^", "{", "}", "|"};
for (String key : fbsArr) {
if (keyword.contains(key)) {
keyword = keyword.replace(key, "\\" + key);
}
}
}
return keyword;
}
private static String formatJson(String json_path){ private static String formatJson(String json_path){
String ret=""; String ret="";
String reg = ".(\\d{1,3}).{0,1}"; String reg = ".(\\d{1,3}).{0,1}";

View File

@ -18,7 +18,7 @@ public class ScriptEngineUtils {
String script = IOUtils.toString(ScriptEngineUtils.class.getResource("/javascript/func.js"), StandardCharsets.UTF_8); String script = IOUtils.toString(ScriptEngineUtils.class.getResource("/javascript/func.js"), StandardCharsets.UTF_8);
engine.eval(script); engine.eval(script);
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
@ -26,7 +26,7 @@ public class ScriptEngineUtils {
try { try {
return engine.eval("calculate('" + input + "')").toString(); return engine.eval("calculate('" + input + "')").toString();
} catch (ScriptException e) { } catch (ScriptException e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
return input; return input;
} }
} }

View File

@ -44,7 +44,7 @@ public class ShiroConfig implements EnvironmentAware {
Map<String, String> filterChainDefinitionMap = shiroFilterFactoryBean.getFilterChainDefinitionMap(); Map<String, String> filterChainDefinitionMap = shiroFilterFactoryBean.getFilterChainDefinitionMap();
ShiroUtils.loadBaseFilterChain(filterChainDefinitionMap); ShiroUtils.loadBaseFilterChain(filterChainDefinitionMap);
filterChainDefinitionMap.put("/display/info", "anon"); filterChainDefinitionMap.put("/display/info", "anon");
filterChainDefinitionMap.put("/display/file/*", "anon"); filterChainDefinitionMap.put("/display/file/**", "anon");
filterChainDefinitionMap.put("/**", "apikey, authc"); filterChainDefinitionMap.put("/**", "apikey, authc");
return shiroFilterFactoryBean; return shiroFilterFactoryBean;
} }

View File

@ -3,6 +3,7 @@ package io.metersphere.controller;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import io.metersphere.base.domain.User; import io.metersphere.base.domain.User;
import io.metersphere.commons.utils.SessionUtils; import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.controller.handler.annotation.NoResultHolder;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -34,6 +35,26 @@ public class TestController {
return jsonObject; return jsonObject;
} }
@NoResultHolder
@GetMapping(value = "/xml")
public String getXmlString() {
return "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n" +
"\n" +
"<bookstore>\n" +
"\n" +
"<book>\n" +
" <title lang=\"eng\">Harry Potter</title>\n" +
" <price>29.99</price>\n" +
"</book>\n" +
"\n" +
"<book>\n" +
" <title lang=\"eng\">Learning XML</title>\n" +
" <price>39.95</price>\n" +
"</book>\n" +
"\n" +
"</bookstore>";
}
@GetMapping(value = "/{str}") @GetMapping(value = "/{str}")
public Object getString(@PathVariable String str) throws InterruptedException { public Object getString(@PathVariable String str) throws InterruptedException {
if (StringUtils.equals("error", str)) { if (StringUtils.equals("error", str)) {

View File

@ -2,6 +2,7 @@ package io.metersphere.controller.handler;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import io.metersphere.controller.ResultHolder; import io.metersphere.controller.ResultHolder;
import io.metersphere.controller.handler.annotation.NoResultHolder;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter;
@ -30,6 +31,10 @@ public class ResultResponseBodyAdvice implements ResponseBodyAdvice<Object> {
return null; return null;
} }
if (methodParameter.hasMethodAnnotation(NoResultHolder.class)) {
return o;
}
if (!(o instanceof ResultHolder)) { if (!(o instanceof ResultHolder)) {
if (o instanceof String) { if (o instanceof String) {
return JSON.toJSONString(ResultHolder.success(o)); return JSON.toJSONString(ResultHolder.success(o));

View File

@ -0,0 +1,15 @@
package io.metersphere.controller.handler.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NoResultHolder {
}

View File

@ -72,13 +72,15 @@ public class AppStartListener implements ApplicationListener<ApplicationReadyEve
*/ */
private void loadJars() { private void loadJars() {
List<JarConfig> jars = jarConfigService.list(); List<JarConfig> jars = jarConfigService.list();
try {
jars.forEach(jarConfig -> { jars.forEach(jarConfig -> {
try {
NewDriverManager.loadJar(jarConfig.getPath()); NewDriverManager.loadJar(jarConfig.getPath());
});
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
LogUtil.error(e.getMessage(), e); LogUtil.error(e.getMessage(), e);
} }
});
} }
} }

View File

@ -19,6 +19,7 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
@Service @Service
@Transactional(propagation = Propagation.NOT_SUPPORTED) @Transactional(propagation = Propagation.NOT_SUPPORTED)
@ -57,13 +58,15 @@ public class DingTaskService {
list.forEach(u -> { list.forEach(u -> {
phoneList.add(u.getPhone()); phoneList.add(u.getPhone());
}); });
at.setAtMobiles(phoneList); LogUtil.info("收件人地址" + phoneList);
List<String> phoneLists = phoneList.stream().distinct().collect(Collectors.toList());
at.setAtMobiles(phoneLists);
request.setAt(at); request.setAt(at);
OapiRobotSendResponse response = null; OapiRobotSendResponse response = null;
try { try {
response = client.execute(request); response = client.execute(request);
} catch (ApiException e) { } catch (ApiException e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
System.out.println(response.getErrcode()); System.out.println(response.getErrcode());
} }

View File

@ -2,10 +2,7 @@ package io.metersphere.notice.service;
import io.metersphere.base.domain.*; import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.UserMapper; import io.metersphere.base.mapper.UserMapper;
import io.metersphere.commons.constants.APITestStatus; import io.metersphere.commons.constants.*;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.ParamConstants;
import io.metersphere.commons.constants.PerformanceTestStatus;
import io.metersphere.commons.user.SessionUser; import io.metersphere.commons.user.SessionUser;
import io.metersphere.commons.utils.EncryptUtils; import io.metersphere.commons.utils.EncryptUtils;
import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.LogUtil;
@ -38,6 +35,7 @@ import javax.mail.internet.MimeMessage;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
@Service @Service
@Transactional(propagation = Propagation.NOT_SUPPORTED) @Transactional(propagation = Propagation.NOT_SUPPORTED)
@ -67,7 +65,7 @@ public class MailService {
} }
sendApiOrLoadNotification(addresseeIdList(messageDetail, userIds, eventType), context, performanceTemplate, loadTestReport.getTriggerMode()); sendApiOrLoadNotification(addresseeIdList(messageDetail, userIds, eventType), context, performanceTemplate, loadTestReport.getTriggerMode());
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
@ -88,7 +86,7 @@ public class MailService {
} }
sendApiOrLoadNotification(addresseeIdList(messageDetail, userIds, eventType), context, apiTemplate, apiTestReport.getTriggerMode()); sendApiOrLoadNotification(addresseeIdList(messageDetail, userIds, eventType), context, apiTemplate, apiTestReport.getTriggerMode());
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
@ -112,13 +110,15 @@ public class MailService {
list.forEach(u -> { list.forEach(u -> {
emails.add(u.getEmail()); emails.add(u.getEmail());
}); });
users = emails.toArray(new String[0]); List<String> email = emails.stream().distinct().collect(Collectors.toList());
users = email.toArray(new String[0]);
LogUtil.info("收件人地址" + users);
helper.setText(getContent(Template, context), true); helper.setText(getContent(Template, context), true);
helper.setTo(users); helper.setTo(users);
try { try {
javaMailSender.send(mimeMessage); javaMailSender.send(mimeMessage);
} catch (MailException e) { } catch (MailException e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
//测试评审 //测试评审
@ -129,7 +129,7 @@ public class MailService {
String endTemplate = IOUtils.toString(this.getClass().getResource("/mail/ReviewEnd.html"), StandardCharsets.UTF_8); String endTemplate = IOUtils.toString(this.getClass().getResource("/mail/ReviewEnd.html"), StandardCharsets.UTF_8);
sendReviewNotice(addresseeIdList(messageDetail, userIds, eventType), context, endTemplate); sendReviewNotice(addresseeIdList(messageDetail, userIds, eventType), context, endTemplate);
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
@ -139,14 +139,15 @@ public class MailService {
String endTemplate = IOUtils.toString(this.getClass().getResource("/mail/ReviewDelete.html"), StandardCharsets.UTF_8); String endTemplate = IOUtils.toString(this.getClass().getResource("/mail/ReviewDelete.html"), StandardCharsets.UTF_8);
sendReviewNotice(addresseeIdList(messageDetail, userIds, eventType), context, endTemplate); sendReviewNotice(addresseeIdList(messageDetail, userIds, eventType), context, endTemplate);
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
public void sendCommentNotice(MessageDetail messageDetail, List<String> userIds, SaveCommentRequest request, TestCaseWithBLOBs testCaseWithBLOBs, String eventType) { public void sendCommentNotice(MessageDetail messageDetail, List<String> userIds, SaveCommentRequest request, TestCaseWithBLOBs testCaseWithBLOBs, String eventType) {
User user = userMapper.selectByPrimaryKey(testCaseWithBLOBs.getMaintainer());
BaseSystemConfigDTO baseSystemConfigDTO = systemParameterService.getBaseInfo(); BaseSystemConfigDTO baseSystemConfigDTO = systemParameterService.getBaseInfo();
Map<String, String> context = new HashMap<>(); Map<String, String> context = new HashMap<>();
context.put("maintainer", testCaseWithBLOBs.getMaintainer()); context.put("maintainer", user.getName());
context.put("testCaseName", testCaseWithBLOBs.getName()); context.put("testCaseName", testCaseWithBLOBs.getName());
context.put("description", request.getDescription()); context.put("description", request.getDescription());
context.put("url", baseSystemConfigDTO.getUrl()); context.put("url", baseSystemConfigDTO.getUrl());
@ -155,7 +156,7 @@ public class MailService {
String commentTemplate = IOUtils.toString(this.getClass().getResource("/mail/ReviewComments.html"), StandardCharsets.UTF_8); String commentTemplate = IOUtils.toString(this.getClass().getResource("/mail/ReviewComments.html"), StandardCharsets.UTF_8);
sendReviewNotice(addresseeIdList(messageDetail, userIds, eventType), context, commentTemplate); sendReviewNotice(addresseeIdList(messageDetail, userIds, eventType), context, commentTemplate);
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
@ -165,7 +166,7 @@ public class MailService {
String reviewerTemplate = IOUtils.toString(this.getClass().getResource("/mail/ReviewInitiate.html"), StandardCharsets.UTF_8); String reviewerTemplate = IOUtils.toString(this.getClass().getResource("/mail/ReviewInitiate.html"), StandardCharsets.UTF_8);
sendReviewNotice(addresseeIdList(messageDetail, userIds, eventType), context, reviewerTemplate); sendReviewNotice(addresseeIdList(messageDetail, userIds, eventType), context, reviewerTemplate);
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
@ -184,7 +185,9 @@ public class MailService {
list.forEach(u -> { list.forEach(u -> {
emails.add(u.getEmail()); emails.add(u.getEmail());
}); });
users = emails.toArray(new String[0]); List<String> email = emails.stream().distinct().collect(Collectors.toList());
users = email.toArray(new String[0]);
LogUtil.info("收件人地址" + users);
helper.setText(getContent(Template, context), true); helper.setText(getContent(Template, context), true);
helper.setTo(users); helper.setTo(users);
if (users.length > 0) { if (users.length > 0) {
@ -196,34 +199,37 @@ public class MailService {
public void sendTestPlanStartNotice(MessageDetail messageDetail, List<String> userIds, AddTestPlanRequest testPlan, String eventType) { public void sendTestPlanStartNotice(MessageDetail messageDetail, List<String> userIds, AddTestPlanRequest testPlan, String eventType) {
Map<String, String> context = getTestPlanContext(testPlan); Map<String, String> context = getTestPlanContext(testPlan);
context.put("creator", testPlan.getCreator()); User user = userMapper.selectByPrimaryKey(testPlan.getCreator());
context.put("creator", user.getName());
try { try {
String endTemplate = IOUtils.toString(this.getClass().getResource("/mail/TestPlanStart.html"), StandardCharsets.UTF_8); String endTemplate = IOUtils.toString(this.getClass().getResource("/mail/TestPlanStart.html"), StandardCharsets.UTF_8);
sendTestPlanNotice(addresseeIdList(messageDetail, userIds, eventType), context, endTemplate); sendTestPlanNotice(addresseeIdList(messageDetail, userIds, eventType), context, endTemplate);
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
public void sendTestPlanEndNotice(MessageDetail messageDetail, List<String> userIds, AddTestPlanRequest testPlan, String eventType) { public void sendTestPlanEndNotice(MessageDetail messageDetail, List<String> userIds, AddTestPlanRequest testPlan, String eventType) {
User user = userMapper.selectByPrimaryKey(testPlan.getCreator());
Map<String, String> context = getTestPlanContext(testPlan); Map<String, String> context = getTestPlanContext(testPlan);
context.put("creator", userIds.toString()); context.put("creator", user.getName());
try { try {
String endTemplate = IOUtils.toString(this.getClass().getResource("/mail/TestPlanEnd.html"), StandardCharsets.UTF_8); String endTemplate = IOUtils.toString(this.getClass().getResource("/mail/TestPlanEnd.html"), StandardCharsets.UTF_8);
sendTestPlanNotice(addresseeIdList(messageDetail, userIds, eventType), context, endTemplate); sendTestPlanNotice(addresseeIdList(messageDetail, userIds, eventType), context, endTemplate);
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
public void sendTestPlanDeleteNotice(MessageDetail messageDetail, List<String> userIds, AddTestPlanRequest testPlan, String eventType) { public void sendTestPlanDeleteNotice(MessageDetail messageDetail, List<String> userIds, AddTestPlanRequest testPlan, String eventType) {
User user = userMapper.selectByPrimaryKey(testPlan.getCreator());
Map<String, String> context = getTestPlanContext(testPlan); Map<String, String> context = getTestPlanContext(testPlan);
context.put("creator", userIds.toString()); context.put("creator", user.getName());
try { try {
String endTemplate = IOUtils.toString(this.getClass().getResource("/mail/TestPlanDelete.html"), StandardCharsets.UTF_8); String endTemplate = IOUtils.toString(this.getClass().getResource("/mail/TestPlanDelete.html"), StandardCharsets.UTF_8);
sendTestPlanNotice(addresseeIdList(messageDetail, userIds, eventType), context, endTemplate); sendTestPlanNotice(addresseeIdList(messageDetail, userIds, eventType), context, endTemplate);
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
@ -242,7 +248,9 @@ public class MailService {
list.forEach(u -> { list.forEach(u -> {
emails.add(u.getEmail()); emails.add(u.getEmail());
}); });
users = emails.toArray(new String[0]); List<String> email = emails.stream().distinct().collect(Collectors.toList());
users = email.toArray(new String[0]);
LogUtil.info("收件人地址" + users);
helper.setText(getContent(Template, context), true); helper.setText(getContent(Template, context), true);
helper.setTo(users); helper.setTo(users);
javaMailSender.send(mimeMessage); javaMailSender.send(mimeMessage);
@ -258,7 +266,7 @@ public class MailService {
String endTemplate = IOUtils.toString(this.getClass().getResource("/mail/IssuesCreate.html"), StandardCharsets.UTF_8); String endTemplate = IOUtils.toString(this.getClass().getResource("/mail/IssuesCreate.html"), StandardCharsets.UTF_8);
sendIssuesNotice(addresseeIdList(messageDetail, userIds, eventType), context, endTemplate); sendIssuesNotice(addresseeIdList(messageDetail, userIds, eventType), context, endTemplate);
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
@ -277,7 +285,9 @@ public class MailService {
list.forEach(u -> { list.forEach(u -> {
emails.add(u.getEmail()); emails.add(u.getEmail());
}); });
users = emails.toArray(new String[0]); List<String> email = emails.stream().distinct().collect(Collectors.toList());
users = email.toArray(new String[0]);
LogUtil.info("收件人地址" + users);
helper.setText(getContent(Template, context), true); helper.setText(getContent(Template, context), true);
helper.setTo(users); helper.setTo(users);
javaMailSender.send(mimeMessage); javaMailSender.send(mimeMessage);
@ -309,6 +319,15 @@ public class MailService {
context.put("start", start); context.put("start", start);
context.put("end", end); context.put("end", end);
context.put("id", reviewRequest.getId()); context.put("id", reviewRequest.getId());
String status = "";
if (StringUtils.equals(TestPlanStatus.Underway.name(), reviewRequest.getStatus())) {
status = "进行中";
} else if (StringUtils.equals(TestPlanStatus.Prepare.name(), reviewRequest.getStatus())) {
status = "未开始";
} else if (StringUtils.equals(TestPlanStatus.Completed.name(), reviewRequest.getStatus())) {
status = "已完成";
}
context.put("status", status);
return context; return context;
} }
@ -335,6 +354,15 @@ public class MailService {
context.put("start", start); context.put("start", start);
context.put("end", end); context.put("end", end);
context.put("id", testPlan.getId()); context.put("id", testPlan.getId());
String status = "";
if (StringUtils.equals(TestPlanStatus.Underway.name(), testPlan.getStatus())) {
status = "进行中";
} else if (StringUtils.equals(TestPlanStatus.Prepare.name(), testPlan.getStatus())) {
status = "未开始";
} else if (StringUtils.equals(TestPlanStatus.Completed.name(), testPlan.getStatus())) {
status = "已完成";
}
context.put("status", status);
User user = userMapper.selectByPrimaryKey(testPlan.getCreator()); User user = userMapper.selectByPrimaryKey(testPlan.getCreator());
context.put("creator", user.getName()); context.put("creator", user.getName());
return context; return context;
@ -399,8 +427,9 @@ public class MailService {
if (StringUtils.isNotBlank(context.get(k))) { if (StringUtils.isNotBlank(context.get(k))) {
template = RegExUtils.replaceAll(template, "\\$\\{" + k + "}", context.get(k)); template = RegExUtils.replaceAll(template, "\\$\\{" + k + "}", context.get(k));
} else { } else {
template = RegExUtils.replaceAll(template, "\\$\\{" + k + "}", ""); template = RegExUtils.replaceAll(template, "\\$\\{" + k + "}", "未设置");
} }
} }
} }
return template; return template;
@ -410,7 +439,7 @@ public class MailService {
List<String> addresseeIdList = new ArrayList<>(); List<String> addresseeIdList = new ArrayList<>();
if (StringUtils.equals(eventType, messageDetail.getEvent())) { if (StringUtils.equals(eventType, messageDetail.getEvent())) {
messageDetail.getUserIds().forEach(u -> { messageDetail.getUserIds().forEach(u -> {
if (!StringUtils.equals(NoticeConstants.EXECUTOR, u) && !StringUtils.equals(NoticeConstants.EXECUTOR, u) && !StringUtils.equals(NoticeConstants.MAINTAINER, u)) { if (!StringUtils.equals(NoticeConstants.EXECUTOR, u) && !StringUtils.equals(NoticeConstants.FOUNDER, u) && !StringUtils.equals(NoticeConstants.MAINTAINER, u)) {
addresseeIdList.add(u); addresseeIdList.add(u);
} }
if (StringUtils.equals(NoticeConstants.CREATE, eventType) && StringUtils.equals(NoticeConstants.EXECUTOR, u)) { if (StringUtils.equals(NoticeConstants.CREATE, eventType) && StringUtils.equals(NoticeConstants.EXECUTOR, u)) {

View File

@ -5,12 +5,15 @@ import io.metersphere.base.domain.MessageTaskExample;
import io.metersphere.base.mapper.MessageTaskMapper; import io.metersphere.base.mapper.MessageTaskMapper;
import io.metersphere.base.mapper.ext.ExtMessageMapper; import io.metersphere.base.mapper.ext.ExtMessageMapper;
import io.metersphere.commons.constants.NoticeConstants; import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.user.SessionUser; import io.metersphere.commons.user.SessionUser;
import io.metersphere.commons.utils.SessionUtils; import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.i18n.Translator;
import io.metersphere.notice.controller.request.MessageRequest; import io.metersphere.notice.controller.request.MessageRequest;
import io.metersphere.notice.domain.MessageDetail; import io.metersphere.notice.domain.MessageDetail;
import io.metersphere.notice.domain.MessageSettingDetail; import io.metersphere.notice.domain.MessageSettingDetail;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -49,6 +52,7 @@ public class NoticeService {
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
String identification = UUID.randomUUID().toString(); String identification = UUID.randomUUID().toString();
list.getUserIds().forEach(m -> { list.getUserIds().forEach(m -> {
checkUserIdExist(m, list,orgId);
MessageTask message = new MessageTask(); MessageTask message = new MessageTask();
message.setId(UUID.randomUUID().toString()); message.setId(UUID.randomUUID().toString());
message.setEvent(list.getEvent()); message.setEvent(list.getEvent());
@ -57,7 +61,7 @@ public class NoticeService {
message.setType(list.getType()); message.setType(list.getType());
message.setWebhook(list.getWebhook()); message.setWebhook(list.getWebhook());
message.setIdentification(identification); message.setIdentification(identification);
message.setIsSet(list.getIsSet()); message.setIsSet(false);
message.setOrganizationId(orgId); message.setOrganizationId(orgId);
message.setTestId(list.getTestId()); message.setTestId(list.getTestId());
message.setCreateTime(time); message.setCreateTime(time);
@ -65,6 +69,18 @@ public class NoticeService {
}); });
} }
private void checkUserIdExist(String userId, MessageDetail list,String orgId) {
MessageTaskExample example = new MessageTaskExample();
if (StringUtils.isBlank(list.getTestId())) {
example.createCriteria().andUserIdEqualTo(userId).andEventEqualTo(list.getEvent()).andTypeEqualTo(list.getType()).andTaskTypeEqualTo(list.getTaskType()).andWebhookEqualTo(list.getWebhook()).andOrganizationIdEqualTo(orgId);
} else {
example.createCriteria().andUserIdEqualTo(userId).andEventEqualTo(list.getEvent()).andTypeEqualTo(list.getType()).andTaskTypeEqualTo(list.getTaskType()).andWebhookEqualTo(list.getWebhook()).andTestIdEqualTo(list.getTestId()).andOrganizationIdEqualTo(orgId);
}
if (messageTaskMapper.countByExample(example) > 0) {
MSException.throwException(Translator.get("message_task_already_exists"));
}
}
public List<MessageDetail> searchMessageSchedule(String testId) { public List<MessageDetail> searchMessageSchedule(String testId) {
List<MessageTask> messageTaskLists = extMessageMapper.searchMessageByTestId(testId); List<MessageTask> messageTaskLists = extMessageMapper.searchMessageByTestId(testId);
List<MessageDetail> scheduleMessageTask = new ArrayList<>(); List<MessageDetail> scheduleMessageTask = new ArrayList<>();
@ -116,10 +132,14 @@ public class NoticeService {
messageDetail.setUserIds(new ArrayList<String>(userIds)); messageDetail.setUserIds(new ArrayList<String>(userIds));
MessageDetailList.add(messageDetail); MessageDetailList.add(messageDetail);
}); });
List<MessageDetail> jenkinsTask = MessageDetailList.stream().filter(a -> a.getTaskType().equals(NoticeConstants.JENKINS_TASK)).sorted(Comparator.comparing(MessageDetail::getCreateTime, Comparator.nullsLast(Long::compareTo)).reversed()).collect(Collectors.toList()); List<MessageDetail> jenkinsTask = (MessageDetailList.stream().filter(a -> a.getTaskType().equals(NoticeConstants.JENKINS_TASK)).sorted(Comparator.comparing(
List<MessageDetail> testCasePlanTask = MessageDetailList.stream().filter(a -> a.getTaskType().equals(NoticeConstants.TEST_PLAN_TASK)).sorted(Comparator.comparing(MessageDetail::getCreateTime, Comparator.nullsLast(Long::compareTo)).reversed()).collect(Collectors.toList()); MessageDetail::getCreateTime, Comparator.nullsLast(Long::compareTo)).reversed()).collect(Collectors.toList())).stream().distinct().collect(Collectors.toList());
List<MessageDetail> reviewTask = MessageDetailList.stream().filter(a -> a.getTaskType().equals(NoticeConstants.REVIEW_TASK)).sorted(Comparator.comparing(MessageDetail::getCreateTime, Comparator.nullsLast(Long::compareTo)).reversed()).collect(Collectors.toList()); List<MessageDetail> testCasePlanTask = (MessageDetailList.stream().filter(a -> a.getTaskType().equals(NoticeConstants.TEST_PLAN_TASK)).sorted(Comparator.comparing(
List<MessageDetail> defectTask = MessageDetailList.stream().filter(a -> a.getTaskType().equals(NoticeConstants.DEFECT_TASK)).sorted(Comparator.comparing(MessageDetail::getCreateTime, Comparator.nullsLast(Long::compareTo)).reversed()).collect(Collectors.toList()); MessageDetail::getCreateTime, Comparator.nullsLast(Long::compareTo)).reversed()).collect(Collectors.toList())).stream().distinct().collect(Collectors.toList());
List<MessageDetail> reviewTask = (MessageDetailList.stream().filter(a -> a.getTaskType().equals(NoticeConstants.REVIEW_TASK)).sorted(Comparator.comparing(
MessageDetail::getCreateTime, Comparator.nullsLast(Long::compareTo)).reversed()).collect(Collectors.toList())).stream().distinct().collect(Collectors.toList());
List<MessageDetail> defectTask = (MessageDetailList.stream().filter(a -> a.getTaskType().equals(NoticeConstants.DEFECT_TASK)).sorted(Comparator.comparing(
MessageDetail::getCreateTime, Comparator.nullsLast(Long::compareTo)).reversed()).collect(Collectors.toList())).stream().distinct().collect(Collectors.toList());
messageSettingDetail.setJenkinsTask(jenkinsTask); messageSettingDetail.setJenkinsTask(jenkinsTask);
messageSettingDetail.setTestCasePlanTask(testCasePlanTask); messageSettingDetail.setTestCasePlanTask(testCasePlanTask);
messageSettingDetail.setReviewTask(reviewTask); messageSettingDetail.setReviewTask(reviewTask);

View File

@ -18,6 +18,7 @@ import javax.annotation.Resource;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
@Service @Service
@Transactional(propagation = Propagation.NOT_SUPPORTED) @Transactional(propagation = Propagation.NOT_SUPPORTED)
@ -50,13 +51,15 @@ public class WxChatTaskService {
list.forEach(u -> { list.forEach(u -> {
phoneList.add(u.getPhone()); phoneList.add(u.getPhone());
}); });
mentionedMobileList.addAll(phoneList); LogUtil.info("收件人地址" + phoneList);
List<String> phoneLists = phoneList.stream().distinct().collect(Collectors.toList());
mentionedMobileList.addAll(phoneLists);
message.setMentionedMobileList(mentionedMobileList); message.setMentionedMobileList(mentionedMobileList);
try { try {
SendResult result = WxChatbotClient.send(Webhook, message); SendResult result = WxChatbotClient.send(Webhook, message);
System.out.println(result); System.out.println(result);
} catch (IOException e) { } catch (IOException e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }

View File

@ -139,10 +139,10 @@ public class EngineFactory {
String content = engineSourceParser.parse(engineContext, source); String content = engineSourceParser.parse(engineContext, source);
engineContext.setContent(content); engineContext.setContent(content);
} catch (MSException e) { } catch (MSException e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
MSException.throwException(e); MSException.throwException(e);
} }

View File

@ -64,10 +64,10 @@ public class DockerTestEngine extends AbstractEngine {
try { try {
context = EngineFactory.createContext(loadTest, resource.getId(), ratio, this.getStartTime(), this.getReportId(), resourceIndex); context = EngineFactory.createContext(loadTest, resource.getId(), ratio, this.getStartTime(), this.getReportId(), resourceIndex);
} catch (MSException e) { } catch (MSException e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
MSException.throwException(e); MSException.throwException(e);
} }

View File

@ -65,7 +65,7 @@ public class PerformanceNoticeTask {
//查询定时任务是否关闭 //查询定时任务是否关闭
Thread.sleep(1000 * 30);// 每分钟检查 loadtest 的状态 Thread.sleep(1000 * 30);// 每分钟检查 loadtest 的状态
} catch (InterruptedException e) { } catch (InterruptedException e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
}); });

View File

@ -258,7 +258,7 @@ public class PerformanceTestService {
soc.close(); soc.close();
} }
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
MSException.throwException(Translator.get("load_test_kafka_invalid")); MSException.throwException(Translator.get("load_test_kafka_invalid"));
} }
} }
@ -304,7 +304,7 @@ public class PerformanceTestService {
} catch (MSException e) { } catch (MSException e) {
// 启动失败之后清理任务 // 启动失败之后清理任务
engine.stop(); engine.stop();
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
loadTest.setStatus(PerformanceTestStatus.Error.name()); loadTest.setStatus(PerformanceTestStatus.Error.name());
loadTest.setDescription(e.getMessage()); loadTest.setDescription(e.getMessage());
loadTestMapper.updateByPrimaryKeySelective(loadTest); loadTestMapper.updateByPrimaryKeySelective(loadTest);

View File

@ -105,6 +105,9 @@ public class ReportService {
example.createCriteria().andReportIdEqualTo(reportId); example.createCriteria().andReportIdEqualTo(reportId);
loadTestReportDetailMapper.deleteByExample(example); loadTestReportDetailMapper.deleteByExample(example);
// delete jtl file
fileService.deleteFileById(loadTestReport.getFileId());
loadTestReportMapper.deleteByPrimaryKey(reportId); loadTestReportMapper.deleteByPrimaryKey(reportId);
} }

View File

@ -119,7 +119,7 @@ public class JarConfigService {
file.createNewFile(); file.createNewFile();
FileUtil.copyStream(in, out); FileUtil.copyStream(in, out);
} catch (IOException e) { } catch (IOException e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
MSException.throwException(Translator.get("upload_fail")); MSException.throwException(Translator.get("upload_fail"));
} }
return filePath; return filePath;

View File

@ -7,6 +7,7 @@ import io.metersphere.base.mapper.ext.ExtSystemParameterMapper;
import io.metersphere.commons.constants.ParamConstants; import io.metersphere.commons.constants.ParamConstants;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.EncryptUtils; import io.metersphere.commons.utils.EncryptUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.dto.BaseSystemConfigDTO; import io.metersphere.dto.BaseSystemConfigDTO;
import io.metersphere.i18n.Translator; import io.metersphere.i18n.Translator;
import io.metersphere.ldap.domain.LdapInfo; import io.metersphere.ldap.domain.LdapInfo;
@ -106,6 +107,7 @@ public class SystemParameterService {
try { try {
javaMailSender.testConnection(); javaMailSender.testConnection();
} catch (MessagingException e) { } catch (MessagingException e) {
LogUtil.error(e.getMessage(), e);
MSException.throwException(Translator.get("connection_failed")); MSException.throwException(Translator.get("connection_failed"));
} }
} }

View File

@ -135,7 +135,7 @@ public class TestResourcePoolService {
MSException.throwException("Resource Pool is invalid."); MSException.throwException("Resource Pool is invalid.");
} }
} catch (IllegalAccessException | InvocationTargetException e) { } catch (IllegalAccessException | InvocationTargetException e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
@ -161,7 +161,7 @@ public class TestResourcePoolService {
testResourcePoolDTO.setResources(testResources); testResourcePoolDTO.setResources(testResources);
testResourcePoolDTOS.add(testResourcePoolDTO); testResourcePoolDTOS.add(testResourcePoolDTO);
} catch (IllegalAccessException | InvocationTargetException e) { } catch (IllegalAccessException | InvocationTargetException e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
}); });
return testResourcePoolDTOS; return testResourcePoolDTOS;
@ -210,7 +210,7 @@ public class TestResourcePoolService {
ResponseEntity<String> entity = restTemplateWithTimeOut.getForEntity(String.format(nodeControllerUrl, node.getIp(), node.getPort()), String.class); ResponseEntity<String> entity = restTemplateWithTimeOut.getForEntity(String.format(nodeControllerUrl, node.getIp(), node.getPort()), String.class);
return HttpStatus.OK.equals(entity.getStatusCode()); return HttpStatus.OK.equals(entity.getStatusCode());
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
return false; return false;
} }
} }

View File

@ -318,6 +318,17 @@ public class UserService {
} }
public void updateUser(User user) { public void updateUser(User user) {
// todo 提取重复代码
if (StringUtils.isNotBlank(user.getEmail())) {
UserExample example = new UserExample();
UserExample.Criteria criteria = example.createCriteria();
criteria.andEmailEqualTo(user.getEmail());
criteria.andIdNotEqualTo(user.getId());
if (userMapper.countByExample(example) > 0) {
MSException.throwException(Translator.get("user_email_already_exists"));
}
}
user.setUpdateTime(System.currentTimeMillis()); user.setUpdateTime(System.currentTimeMillis());
userMapper.updateByPrimaryKeySelective(user); userMapper.updateByPrimaryKeySelective(user);
// 禁用用户之后剔除在线用户 // 禁用用户之后剔除在线用户
@ -424,8 +435,12 @@ public class UserService {
} }
public void delOrganizationMember(String organizationId, String userId) { public void delOrganizationMember(String organizationId, String userId) {
List<String> resourceIds = workspaceService.getWorkspaceIdsOrgId(organizationId);
resourceIds.add(organizationId);
UserRoleExample userRoleExample = new UserRoleExample(); UserRoleExample userRoleExample = new UserRoleExample();
userRoleExample.createCriteria().andRoleIdLike("%org%").andUserIdEqualTo(userId).andSourceIdEqualTo(organizationId); userRoleExample.createCriteria().andUserIdEqualTo(userId).andSourceIdIn(resourceIds);
User user = userMapper.selectByPrimaryKey(userId); User user = userMapper.selectByPrimaryKey(userId);
if (StringUtils.equals(organizationId, user.getLastOrganizationId())) { if (StringUtils.equals(organizationId, user.getLastOrganizationId())) {

View File

@ -202,6 +202,10 @@ public class WorkspaceService {
return resultWorkspaceList; return resultWorkspaceList;
} }
public List<String> getWorkspaceIdsOrgId(String orgId) {
return extWorkspaceMapper.getWorkspaceIdsByOrgId(orgId);
}
public void updateWorkspaceMember(WorkspaceMemberDTO memberDTO) { public void updateWorkspaceMember(WorkspaceMemberDTO memberDTO) {
String workspaceId = memberDTO.getWorkspaceId(); String workspaceId = memberDTO.getWorkspaceId();
String userId = memberDTO.getId(); String userId = memberDTO.getId();

View File

@ -1,26 +0,0 @@
package io.metersphere.track.issue;
import io.metersphere.commons.utils.EncryptUtils;
public class ZentaoUtils {
/**
* @param code Zentao 应用代号
* @param key Zentao 密钥
* @return token
*/
public static String getToken(String code, String key, String time) {
return (String) EncryptUtils.md5Encrypt(code + key + time);
}
/**
* @param url Zentao url
* @param code Zentao 应用代号
* @param key Zentao 密钥
* @return url
*/
public static String getUrl(String url, String code, String key) {
String time = String.valueOf(System.currentTimeMillis());;
return url + "api.php?" + "code=" + code + "&time=" + time + "&token=" + getToken(code, key, time);
}
}

View File

@ -116,7 +116,7 @@ public class IssuesService {
} }
}); });
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }

View File

@ -3,8 +3,10 @@ package io.metersphere.track.service;
import io.metersphere.base.domain.TestCaseComment; import io.metersphere.base.domain.TestCaseComment;
import io.metersphere.base.domain.TestCaseCommentExample; import io.metersphere.base.domain.TestCaseCommentExample;
import io.metersphere.base.domain.TestCaseWithBLOBs; import io.metersphere.base.domain.TestCaseWithBLOBs;
import io.metersphere.base.domain.User;
import io.metersphere.base.mapper.TestCaseCommentMapper; import io.metersphere.base.mapper.TestCaseCommentMapper;
import io.metersphere.base.mapper.TestCaseMapper; import io.metersphere.base.mapper.TestCaseMapper;
import io.metersphere.base.mapper.UserMapper;
import io.metersphere.base.mapper.ext.ExtTestCaseCommentMapper; import io.metersphere.base.mapper.ext.ExtTestCaseCommentMapper;
import io.metersphere.commons.constants.NoticeConstants; import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
@ -48,7 +50,8 @@ public class TestCaseCommentService {
private NoticeService noticeService; private NoticeService noticeService;
@Resource @Resource
private ExtTestCaseCommentMapper extTestCaseCommentMapper; private ExtTestCaseCommentMapper extTestCaseCommentMapper;
@Resource
private UserMapper userMapper;
public void saveComment(SaveCommentRequest request) { public void saveComment(SaveCommentRequest request) {
TestCaseComment testCaseComment = new TestCaseComment(); TestCaseComment testCaseComment = new TestCaseComment();
@ -81,7 +84,7 @@ public class TestCaseCommentService {
} }
}); });
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
@ -97,6 +100,7 @@ public class TestCaseCommentService {
} }
private String getReviewContext(TestCaseComment testCaseComment, TestCaseWithBLOBs testCaseWithBLOBs) { private String getReviewContext(TestCaseComment testCaseComment, TestCaseWithBLOBs testCaseWithBLOBs) {
User user = userMapper.selectByPrimaryKey(testCaseComment.getAuthor());
Long startTime = testCaseComment.getCreateTime(); Long startTime = testCaseComment.getCreateTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String start = null; String start = null;
@ -105,7 +109,7 @@ public class TestCaseCommentService {
start = sdf.format(new Date(Long.parseLong(sTime))); start = sdf.format(new Date(Long.parseLong(sTime)));
} }
String context = ""; String context = "";
context = "测试评审任务通知:" + testCaseComment.getAuthor() + "" + start + "" + "'" + testCaseWithBLOBs.getName() + "'" + "添加评论:" + testCaseComment.getDescription(); context = "测试评审任务通知:" + user.getName() + "" + start + "" + "'" + testCaseWithBLOBs.getName() + "'" + "添加评论:" + testCaseComment.getDescription();
return context; return context;
} }

View File

@ -127,7 +127,7 @@ public class TestCaseReviewService {
} }
}); });
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
@ -187,7 +187,6 @@ public class TestCaseReviewService {
testCaseReviewMapper.updateByPrimaryKeySelective(testCaseReview); testCaseReviewMapper.updateByPrimaryKeySelective(testCaseReview);
List<String> userIds = new ArrayList<>(); List<String> userIds = new ArrayList<>();
userIds.addAll(testCaseReview.getUserIds()); userIds.addAll(testCaseReview.getUserIds());
if (StringUtils.equals(TestPlanStatus.Completed.name(), testCaseReview.getStatus())) {
try { try {
String context = getReviewContext(testCaseReview, NoticeConstants.UPDATE); String context = getReviewContext(testCaseReview, NoticeConstants.UPDATE);
MessageSettingDetail messageSettingDetail = noticeService.searchMessage(); MessageSettingDetail messageSettingDetail = noticeService.searchMessage();
@ -201,13 +200,12 @@ public class TestCaseReviewService {
wxChatTaskService.sendWechatRobot(r, userIds, context, NoticeConstants.UPDATE); wxChatTaskService.sendWechatRobot(r, userIds, context, NoticeConstants.UPDATE);
break; break;
case NoticeConstants.EMAIL: case NoticeConstants.EMAIL:
mailService.sendReviewerNotice(r, userIds, testCaseReview, NoticeConstants.UPDATE); mailService.sendEndNotice(r, userIds, testCaseReview, NoticeConstants.UPDATE);
break; break;
} }
}); });
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
}
} }
} }
@ -318,7 +316,7 @@ public class TestCaseReviewService {
} }
}); });
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
@ -468,7 +466,7 @@ public class TestCaseReviewService {
} }
}); });
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
} }
@ -572,16 +570,28 @@ public class TestCaseReviewService {
String eTime = String.valueOf(endTime); String eTime = String.valueOf(endTime);
if (!sTime.equals("null")) { if (!sTime.equals("null")) {
start = sdf.format(new Date(Long.parseLong(sTime))); start = sdf.format(new Date(Long.parseLong(sTime)));
} else {
start = "未设置";
} }
String end = null; String end = null;
if (!eTime.equals("null")) { if (!eTime.equals("null")) {
end = sdf.format(new Date(Long.parseLong(eTime))); end = sdf.format(new Date(Long.parseLong(eTime)));
} else {
start = "未设置";
} }
String context = ""; String context = "";
if (StringUtils.equals(NoticeConstants.CREATE, type)) { if (StringUtils.equals(NoticeConstants.CREATE, type)) {
context = "测试评审任务通知:" + user.getName() + "发起的" + "'" + reviewRequest.getName() + "'" + "待开始,计划开始时间是" + start + "计划结束时间为" + end + "请跟进"; context = "测试评审任务通知:" + user.getName() + "发起的" + "'" + reviewRequest.getName() + "'" + "待开始,计划开始时间是" + start + "计划结束时间为" + end + "请跟进";
} else if (StringUtils.equals(NoticeConstants.UPDATE, type)) { } else if (StringUtils.equals(NoticeConstants.UPDATE, type)) {
context = "测试评审任务通知:" + user.getName() + "发起的" + "'" + reviewRequest.getName() + "'" + "已完成,计划开始时间是" + start + "计划结束时间为" + end + "已完成"; String status = "";
if (StringUtils.equals(TestPlanStatus.Underway.name(), reviewRequest.getStatus())) {
status = "进行中";
} else if (StringUtils.equals(TestPlanStatus.Prepare.name(), reviewRequest.getStatus())) {
status = "未开始";
} else if (StringUtils.equals(TestPlanStatus.Completed.name(), reviewRequest.getStatus())) {
status = "已完成";
}
context = "测试评审任务通知:" + user.getName() + "发起的" + "'" + reviewRequest.getName() + "'" + "计划开始时间是" + start + "计划结束时间为" + end + status;
} else if (StringUtils.equals(NoticeConstants.DELETE, type)) { } else if (StringUtils.equals(NoticeConstants.DELETE, type)) {
context = "测试评审任务通知:" + user.getName() + "发起的" + "'" + reviewRequest.getName() + "'" + "计划开始时间是" + start + "计划结束时间为" + end + "已删除"; context = "测试评审任务通知:" + user.getName() + "发起的" + "'" + reviewRequest.getName() + "'" + "计划开始时间是" + start + "计划结束时间为" + end + "已删除";
} }

View File

@ -137,7 +137,7 @@ public class TestPlanService {
} }
}); });
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
@ -159,13 +159,16 @@ public class TestPlanService {
//进行中状态写入实际开始时间 //进行中状态写入实际开始时间
if (TestPlanStatus.Underway.name().equals(testPlan.getStatus())) { if (TestPlanStatus.Underway.name().equals(testPlan.getStatus())) {
testPlan.setActualStartTime(System.currentTimeMillis()); testPlan.setActualStartTime(System.currentTimeMillis());
} else if (TestPlanStatus.Completed.name().equals(testPlan.getStatus())) { } else if (TestPlanStatus.Completed.name().equals(testPlan.getStatus())) {
//已完成写入实际完成时间
testPlan.setActualEndTime(System.currentTimeMillis());
}
List<String> userIds = new ArrayList<>(); List<String> userIds = new ArrayList<>();
userIds.add(testPlan.getPrincipal()); userIds.add(testPlan.getPrincipal());
AddTestPlanRequest testPlans = new AddTestPlanRequest(); AddTestPlanRequest testPlans = new AddTestPlanRequest();
//已完成写入实际完成时间 int i = testPlanMapper.updateByPrimaryKeySelective(testPlan);
testPlan.setActualEndTime(System.currentTimeMillis()); if (!StringUtils.isBlank(testPlan.getStatus())) {
try { try {
BeanUtils.copyBean(testPlans, getTestPlan(testPlan.getId())); BeanUtils.copyBean(testPlans, getTestPlan(testPlan.getId()));
String context = getTestPlanContext(testPlans, NoticeConstants.UPDATE); String context = getTestPlanContext(testPlans, NoticeConstants.UPDATE);
@ -180,16 +183,15 @@ public class TestPlanService {
wxChatTaskService.sendWechatRobot(r, userIds, context, NoticeConstants.UPDATE); wxChatTaskService.sendWechatRobot(r, userIds, context, NoticeConstants.UPDATE);
break; break;
case NoticeConstants.EMAIL: case NoticeConstants.EMAIL:
mailService.sendTestPlanStartNotice(r, userIds, testPlans, NoticeConstants.UPDATE); mailService.sendTestPlanEndNotice(r, userIds, testPlans, NoticeConstants.UPDATE);
break; break;
} }
}); });
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
return i;
return testPlanMapper.updateByPrimaryKeySelective(testPlan);
} }
private void editTestPlanProject(TestPlanDTO testPlan) { private void editTestPlanProject(TestPlanDTO testPlan) {
@ -270,7 +272,7 @@ public class TestPlanService {
} }
}); });
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
return num; return num;
} }
@ -511,7 +513,7 @@ public class TestPlanService {
} }
}); });
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
@ -547,21 +549,29 @@ public class TestPlanService {
if (!sTime.equals("null")) { if (!sTime.equals("null")) {
start = sdf.format(new Date(Long.parseLong(sTime))); start = sdf.format(new Date(Long.parseLong(sTime)));
} else { } else {
start = ""; start = "未设置";
} }
String end = null; String end = null;
if (!eTime.equals("null")) { if (!eTime.equals("null")) {
end = sdf.format(new Date(Long.parseLong(eTime))); end = sdf.format(new Date(Long.parseLong(eTime)));
} else { } else {
end = ""; end = "未设置";
} }
String context = ""; String context = "";
if (StringUtils.equals(NoticeConstants.CREATE, type)) { if (StringUtils.equals(NoticeConstants.CREATE, type)) {
context = "测试计划任务通知:" + user.getName() + "创建的" + "'" + testPlan.getName() + "'" + "待开始,计划开始时间是" + start + "计划结束时间为" + end + "请跟进"; context = "测试计划任务通知:" + user.getName() + "创建的" + "'" + testPlan.getName() + "'" + "待开始,计划开始时间是:" + "'" + start + "'" + ";" + "计划结束时间是:" + "'" + end + "'" + " " + "请跟进";
} else if (StringUtils.equals(NoticeConstants.UPDATE, type)) { } else if (StringUtils.equals(NoticeConstants.UPDATE, type)) {
context = "测试计划任务通知:" + user.getName() + "创建的" + "'" + testPlan.getName() + "'" + "已完成,计划开始时间是" + start + "计划结束时间为" + end + "已完成"; String status = "";
if (StringUtils.equals(TestPlanStatus.Underway.name(), testPlan.getStatus())) {
status = "进行中";
} else if (StringUtils.equals(TestPlanStatus.Prepare.name(), testPlan.getStatus())) {
status = "未开始";
} else if (StringUtils.equals(TestPlanStatus.Completed.name(), testPlan.getStatus())) {
status = "已完成";
}
context = "测试计划任务通知:" + user.getName() + "创建的" + "'" + testPlan.getName() + "'" + "计划开始时间是:" + "'" + start + "'" + ";" + "计划结束时间是:" + "'" + end + "'" + " " + status;
} else if (StringUtils.equals(NoticeConstants.DELETE, type)) { } else if (StringUtils.equals(NoticeConstants.DELETE, type)) {
context = "测试计划任务通知:" + user.getName() + "创建的" + "'" + testPlan.getName() + "'" + "计划开始时间是" + start + "计划结束时间为" + end + "已删除"; context = "测试计划任务通知:" + user.getName() + "创建的" + "'" + testPlan.getName() + "'" + "计划开始时间是:" + "'" + start + "'" + ";" + "计划结束时间是:" + "'" + end + "'" + " " + "已删除";
} }
return context; return context;
} }

View File

@ -129,10 +129,8 @@ public class TestPlanTestCaseService {
request.setExecutor(user.getId()); request.setExecutor(user.getId());
} }
public TestPlanCaseDTO get(String caseId) { public TestPlanCaseDTO get(String testplanTestCaseId) {
QueryTestPlanCaseRequest request = new QueryTestPlanCaseRequest(); return extTestPlanTestCaseMapper.get(testplanTestCaseId);
request.setId(caseId);
return extTestPlanTestCaseMapper.list(request).get(0);
} }
public void deleteTestCaseBath(TestPlanCaseBatchRequest request) { public void deleteTestCaseBath(TestPlanCaseBatchRequest request) {

View File

@ -106,7 +106,7 @@ public class ReportWebSocket {
} }
Thread.sleep(20 * 1000L); Thread.sleep(20 * 1000L);
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e.getMessage(), e);
} }
} }
} }

View File

@ -231,7 +231,7 @@ public class XmindCaseParser {
JSONObject step = new JSONObject(true); JSONObject step = new JSONObject(true);
step.put("num", i + 1); step.put("num", i + 1);
step.put("desc", attacheds.get(i).getTitle()); step.put("desc", attacheds.get(i).getTitle());
if (attacheds.get(i) != null && attacheds.get(i).getChildren() != null && attacheds.get(i).getChildren().getAttached()!=null) { if (attacheds.get(i) != null && attacheds.get(i).getChildren() != null && attacheds.get(i).getChildren().getAttached() != null) {
step.put("result", attacheds.get(i).getChildren().getAttached().get(0).getTitle()); step.put("result", attacheds.get(i).getChildren().getAttached().get(0).getTitle());
} }
jsonArray.add(step); jsonArray.add(step);
@ -283,17 +283,20 @@ public class XmindCaseParser {
// 测试步骤处理 // 测试步骤处理
List<Attached> steps = new LinkedList<>(); List<Attached> steps = new LinkedList<>();
StringBuilder rc = new StringBuilder();
if (attacheds != null && !attacheds.isEmpty()) { if (attacheds != null && !attacheds.isEmpty()) {
attacheds.forEach(item -> { attacheds.forEach(item -> {
if (isAvailable(item.getTitle(), PC_REGEX)) { if (isAvailable(item.getTitle(), PC_REGEX)) {
testCase.setPrerequisite(replace(item.getTitle(), PC_REGEX)); testCase.setPrerequisite(replace(item.getTitle(), PC_REGEX));
} else if (isAvailable(item.getTitle(), RC_REGEX)) { } else if (isAvailable(item.getTitle(), RC_REGEX)) {
testCase.setRemark(replace(item.getTitle(), RC_REGEX)); rc.append(replace(item.getTitle(), RC_REGEX));
rc.append("\n");
} else { } else {
steps.add(item); steps.add(item);
} }
}); });
} }
testCase.setRemark(rc.toString());
testCase.setSteps(this.getSteps(steps)); testCase.setSteps(this.getSteps(steps));
testCases.add(testCase); testCases.add(testCase);
// 校验合规性 // 校验合规性

@ -1 +1 @@
Subproject commit 419c75bca64b7c5bfbd1194d7f0fd9919f0caa04 Subproject commit bb494fc68a2367359c9048fa7250c7618de4afb6

View File

@ -170,6 +170,7 @@ test_plan_notification=Test plan notification
task_defect_notification=Task defect notification task_defect_notification=Task defect notification
task_notification_jenkins=Jenkins Task notification task_notification_jenkins=Jenkins Task notification
task_notification=Result notification task_notification=Result notification
message_task_already_exists=Task recipient already exists

View File

@ -171,3 +171,4 @@ test_plan_notification=测试计划通知
task_defect_notification=缺陷任务通知 task_defect_notification=缺陷任务通知
task_notification_jenkins=jenkins任务通知 task_notification_jenkins=jenkins任务通知
task_notification=任务通知 task_notification=任务通知
message_task_already_exists=任务接收人已经存在

View File

@ -172,4 +172,5 @@ test_plan_notification=測試計畫通知
task_defect_notification=缺陷任務通知 task_defect_notification=缺陷任務通知
task_notification_jenkins=jenkins任務通知 task_notification_jenkins=jenkins任務通知
task_notification=任務通知 task_notification=任務通知
message_task_already_exists=任務接收人已經存在

View File

@ -6,7 +6,7 @@
</head> </head>
<body> <body>
<div> <div>
<p style="text-align: left"> ${maintainer} 维护的<br/> <p style="text-align: left"> ${maintainer} <br/>
${testCaseName}<br/> ${testCaseName}<br/>
添加评论:${description}<br/> 添加评论:${description}<br/>
点击下面链接进入用例评审页面</p> 点击下面链接进入用例评审页面</p>

View File

@ -7,10 +7,10 @@
<body> <body>
<div> <div>
<p style="text-align: left">${creator} 发起的:<br> <p style="text-align: left">${creator} 发起的:<br>
${reviewName}已完成<br> ${reviewName}<br>
计划开始时间是:${start}<br> 计划开始时间是:${start}<br>
计划结束时间为:${end}<br> 计划结束时间为:${end}<br>
已完成<br> ${status}<br>
点击下面链接进入用例评审页面</p> 点击下面链接进入用例评审页面</p>
<a href="${url}/#/track/review/view">${url}/#/track/review/view</a> <a href="${url}/#/track/review/view">${url}/#/track/review/view</a>
</div> </div>

View File

@ -7,10 +7,10 @@
<body> <body>
<div> <div>
<p style="text-align: left">${creator} 创建的:<br> <p style="text-align: left">${creator} 创建的:<br>
${testPlanName}已完成<br> ${testPlanName}<br>
计划开始时间是:${start}<br> 计划开始时间是:${start}<br>
计划结束时间为:${end}<br> 计划结束时间为:${end}<br>
已完成<br> ${status}<br>
点击下面链接进入测试计划页面</p> 点击下面链接进入测试计划页面</p>
<a href="${url}/#/track/plan/view/${id}">${url}/#/track/plan/view</a> <a href="${url}/#/track/plan/view/${id}">${url}/#/track/plan/view</a>
</div> </div>

View File

@ -7,8 +7,7 @@
</el-row> </el-row>
<el-row id="header-top" type="flex" justify="space-between" align="middle"> <el-row id="header-top" type="flex" justify="space-between" align="middle">
<el-col :span="12"> <el-col :span="12">
<img v-if="logoId" :src="'/display/file/' + logoId" style="width: 156px;height: 37px;" alt=""> <img :src="'/display/file/logo'" style="width: 156px;height: 37px;" alt="">
<a v-else class="logo"/>
<ms-top-menus/> <ms-top-menus/>
</el-col> </el-col>

View File

@ -46,10 +46,9 @@ import MsScenarioResults from "./components/ScenarioResults";
import MsContainer from "@/business/components/common/components/MsContainer"; import MsContainer from "@/business/components/common/components/MsContainer";
import MsMainContainer from "@/business/components/common/components/MsMainContainer"; import MsMainContainer from "@/business/components/common/components/MsMainContainer";
import MsApiReportExport from "./ApiReportExport"; import MsApiReportExport from "./ApiReportExport";
import {exportPdf} from "@/common/js/utils";
import html2canvas from "html2canvas";
import MsApiReportViewHeader from "./ApiReportViewHeader"; import MsApiReportViewHeader from "./ApiReportViewHeader";
import {RequestFactory} from "../test/model/ScenarioModel"; import {RequestFactory} from "../test/model/ScenarioModel";
import {windowPrint} from "../../../../common/js/utils";
export default { export default {
name: "MsApiReportViewDetail", name: "MsApiReportViewDetail",
@ -154,23 +153,16 @@ export default {
this.scenarioName = requestResult.scenarioName; this.scenarioName = requestResult.scenarioName;
}); });
}, },
handleExport(name) { handleExport() {
this.loading = true;
this.reportExportVisible = true; this.reportExportVisible = true;
let reset = this.exportReportReset; let reset = this.exportReportReset;
this.$nextTick(() => {
this.$nextTick(function () { windowPrint('apiTestReport', 0.57);
html2canvas(document.getElementById('apiTestReport'), {
// scale: 2,
}).then(function (canvas) {
exportPdf(name, [canvas]);
reset(); reset();
}); });
});
}, },
exportReportReset() { exportReportReset() {
this.reportExportVisible = false; this.$router.go(0);
this.loading = false;
} }
}, },

View File

@ -117,6 +117,12 @@
} }
}, },
watch: {
'request.responseResult'() {
this.reload();
}
},
computed: { computed: {
assertion() { assertion() {
return this.request.passAssertions + " / " + this.request.totalAssertions; return this.request.passAssertions + " / " + this.request.totalAssertions;

View File

@ -7,8 +7,8 @@
<el-collapse-transition> <el-collapse-transition>
<el-tabs v-model="activeName" v-show="isActive"> <el-tabs v-model="activeName" v-show="isActive">
<el-tab-pane :class="'body-pane'" label="Body" name="body" class="pane"> <el-tab-pane :class="'body-pane'" label="Body" name="body" class="pane">
<ms-sql-result-table v-if="isSqlType" :body="response.body"/> <ms-sql-result-table v-if="isSqlType && mode == 'table'" :body="response.body"/>
<ms-code-edit v-if="!isSqlType" :mode="mode" :read-only="true" :data="response.body" :modes="modes" ref="codeEdit"/> <ms-code-edit v-if="mode != 'table'" :mode="mode" :read-only="true" :data="response.body" :modes="modes" ref="codeEdit"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="Headers" name="headers" class="pane"> <el-tab-pane label="Headers" name="headers" class="pane">
<pre>{{ response.headers }}</pre> <pre>{{ response.headers }}</pre>
@ -21,9 +21,10 @@
<pre>{{response.vars}}</pre> <pre>{{response.vars}}</pre>
</el-tab-pane> </el-tab-pane>
<el-tab-pane v-if="activeName == 'body' && !isSqlType" :disabled="true" name="mode" class="pane assertions"> <el-tab-pane v-if="activeName == 'body'" :disabled="true" name="mode" class="pane assertions">
<template v-slot:label> <template v-slot:label>
<ms-dropdown :commands="modes" :default-command="mode" @command="modeChange"/> <ms-dropdown v-if="!isSqlType" :commands="modes" :default-command="mode" @command="modeChange"/>
<ms-dropdown v-if="isSqlType" :commands="sqlModes" :default-command="mode" @command="sqlModeChange"/>
</template> </template>
</el-tab-pane> </el-tab-pane>
@ -59,6 +60,7 @@ export default {
isActive: true, isActive: true,
activeName: "body", activeName: "body",
modes: ['text', 'json', 'xml', 'html'], modes: ['text', 'json', 'xml', 'html'],
sqlModes: ['text', 'table'],
mode: BODY_FORMAT.TEXT mode: BODY_FORMAT.TEXT
} }
}, },
@ -69,6 +71,9 @@ export default {
}, },
modeChange(mode) { modeChange(mode) {
this.mode = mode; this.mode = mode;
},
sqlModeChange(mode) {
this.mode = mode;
} }
}, },

View File

@ -1,10 +1,13 @@
<template> <template>
<div>
<el-table <el-table
:data="tableData" v-for="(table, index) in tables"
:key="index"
:data="table.tableData"
border border
size="mini" size="mini"
highlight-current-row> highlight-current-row>
<el-table-column v-for="(title, index) in titles" :key="index" :label="title" min-width="15%"> <el-table-column v-for="(title, index) in table.titles" :key="index" :label="title" min-width="150px">
<template v-slot:default="scope"> <template v-slot:default="scope">
<el-popover <el-popover
placement="top" placement="top"
@ -17,6 +20,7 @@
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</div>
</template> </template>
<script> <script>
@ -24,7 +28,7 @@
name: "MsSqlResultTable", name: "MsSqlResultTable",
data() { data() {
return { return {
tableData: [], tables: [],
titles: [] titles: []
} }
}, },
@ -36,29 +40,71 @@
return; return;
} }
let rowArry = this.body.split("\n"); let rowArry = this.body.split("\n");
let title; this.getTableData(rowArry);
if (this.tables.length > 1) {
for (let i = 0; i < this.tables.length; i++) {
if (this.tables[i].titles.length === 1 && i < this.tables.length - 1) {
this.tables[i].tableData.splice(this.tables[i].tableData.length - 1, 1);
}
}
let lastTable = this.tables[this.tables.length - 1];
if (lastTable.titles.length === 1) {
if (lastTable.tableData.length > 4) {
lastTable.tableData.splice(lastTable.tableData.length - 4, 4);
} else {
this.tables.splice(this.tables.length - 1, 1);
}
} else {
this.tables.splice(this.tables.length - 1, 1);
}
} else {
let table = this.tables[0];
table.tableData.splice(table.tableData.length - 4, 4);
}
},
methods: {
getTableData(rowArry) {
let titles;
let result = []; let result = [];
for (let i = 0; i < rowArry.length; i++) { for (let i = 0; i < rowArry.length; i++) {
let colArray = rowArry[i].split("\t"); let colArray = rowArry[i].split("\t");
if (i === 0) { if (i === 0) {
title = colArray; titles = colArray;
} else {
if (colArray.length != titles.length) {
//
if (colArray.length === 1 && colArray[0] === '') {
this.getTableData(rowArry.slice(i + 1));
} else {
this.getTableData(rowArry.slice(i));
}
break;
} else { } else {
let item = {}; let item = {};
for (let j = 0; j < colArray.length; j++) { for (let j = 0; j < colArray.length; j++) {
item[title[j]] = (colArray[j] ? colArray[j] : ""); item[titles[j]] = (colArray[j] ? colArray[j] : "");
} }
result.push(item); result.push(item);
} }
} }
this.titles = title; }
this.tableData = result;
this.tableData.splice(this.tableData.length - 3, 3); this.tables.splice(0, 0, {
titles: titles,
tableData: result
});
}
} }
} }
</script> </script>
<style scoped> <style scoped>
.el-table {
margin-bottom: 20px;
}
.el-table >>> .cell { .el-table >>> .cell {
white-space: nowrap; white-space: nowrap;
} }

View File

@ -171,7 +171,11 @@ export default {
let scenarios = []; let scenarios = [];
this.test.scenarioDefinition.forEach(scenario => { this.test.scenarioDefinition.forEach(scenario => {
if (scenario.isReference()) { if (scenario.isReference()) {
if (scenarioMap[scenario.id]) scenarios.push(scenarioMap[scenario.id]); if (scenarioMap[scenario.id]) {
let item = scenarioMap[scenario.id];
item.referenceEnable = scenario.referenceEnable;
scenarios.push(item);
}
} else { } else {
scenarios.push(scenario); scenarios.push(scenario);
} }

View File

@ -118,7 +118,7 @@
validateDomain(domain) { validateDomain(domain) {
let strRegex = "^(?=^.{3,255}$)(http(s)?:\\/\\/)?(www\\.)?[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:\\d+)*(\\/\\w+\\.\\w+)*$"; let strRegex = "^(?=^.{3,255}$)(http(s)?:\\/\\/)?(www\\.)?[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:\\d+)*(\\/\\w+\\.\\w+)*$";
const re = new RegExp(strRegex); const re = new RegExp(strRegex);
if (re.test(domain) && domain.length < 26) { if (re.test(domain) && domain.length < 67) {
return true; return true;
} }
this.$warning(this.$t('load_test.input_domain')); this.$warning(this.$t('load_test.input_domain'));

View File

@ -5,7 +5,7 @@
<ms-api-collapse v-model="activeName" @change="handleChange"> <ms-api-collapse v-model="activeName" @change="handleChange">
<draggable :list="scenarios" group="Scenario" class="scenario-draggable" ghost-class="scenario-ghost"> <draggable :list="scenarios" group="Scenario" class="scenario-draggable" ghost-class="scenario-ghost">
<ms-api-collapse-item v-for="(scenario, index) in scenarios" :key="index" <ms-api-collapse-item v-for="(scenario, index) in scenarios" :key="index"
:title="scenario.name" :name="index" :class="{'disable-scenario': !scenario.enable}"> :title="scenario.name" :name="index" :class="{'disable-scenario': !scenario.isEnable()}">
<template slot="title"> <template slot="title">
<div class="scenario-name"> <div class="scenario-name">
<el-tag type="info" size="small" v-if="scenario.isReference()">{{ <el-tag type="info" size="small" v-if="scenario.isReference()">{{
@ -26,11 +26,11 @@
<el-dropdown-item :disabled="isReadOnly" :command="{type:'delete', index:index}"> <el-dropdown-item :disabled="isReadOnly" :command="{type:'delete', index:index}">
{{ $t('api_test.scenario.delete') }} {{ $t('api_test.scenario.delete') }}
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item v-if="scenario.enable" :disabled="isReadOnly" <el-dropdown-item v-if="scenario.isEnable()" :disabled="isReadOnly"
:command="{type:'disable', index:index}"> :command="{type:'disable', index:index}">
{{ $t('api_test.scenario.disable') }} {{ $t('api_test.scenario.disable') }}
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item v-if="!scenario.enable" :disabled="isReadOnly" <el-dropdown-item v-if="!scenario.isEnable()" :disabled="isReadOnly"
:command="{type:'enable', index:index}"> :command="{type:'enable', index:index}">
{{ $t('api_test.scenario.enable') }} {{ $t('api_test.scenario.enable') }}
</el-dropdown-item> </el-dropdown-item>
@ -156,10 +156,20 @@ export default {
} }
}, },
disableScenario(index) { disableScenario(index) {
this.scenarios[index].enable = false; let scenario = this.scenarios[index];
if (scenario.isReference()) {
scenario.referenceEnable = false;
} else {
scenario.enable = false;
}
}, },
enableScenario(index) { enableScenario(index) {
this.scenarios[index].enable = true; let scenario = this.scenarios[index];
if (scenario.isReference()) {
scenario.referenceEnable = true;
} else {
scenario.enable = true;
}
}, },
handleChange(index) { handleChange(index) {
this.select(this.scenarios[index]); this.select(this.scenarios[index]);

View File

@ -72,6 +72,7 @@ export default {
methods: { methods: {
search() { search() {
this.condition.excludeId = this.excludeId; this.condition.excludeId = this.excludeId;
this.condition.projectId = this.projectId;
let url = "/api/list/" + this.currentPage + "/" + this.pageSize; let url = "/api/list/" + this.currentPage + "/" + this.pageSize;
this.result = this.$post(url, this.condition, response => { this.result = this.$post(url, this.condition, response => {
let data = response.data; let data = response.data;

View File

@ -2,7 +2,7 @@
<div> <div>
<el-row :gutter="10" type="flex" justify="space-between" align="middle"> <el-row :gutter="10" type="flex" justify="space-between" align="middle">
<el-col> <el-col>
<el-input :disabled="isReadOnly" :value="value" v-bind="$attrs" step="100" size="small" type="number" @change="change" @input="input" <el-input :disabled="isReadOnly" :value="value" v-bind="$attrs" step="100" size="small" type="number" @change="change" @input="input" :min="0"
:placeholder="$t('api_test.request.assertions.response_in_time')"/> :placeholder="$t('api_test.request.assertions.response_in_time')"/>
</el-col> </el-col>
<el-col class="assertion-btn"> <el-col class="assertion-btn">
@ -35,17 +35,28 @@
methods: { methods: {
add() { add() {
if (this.validate()) {
this.duration.value = this.value; this.duration.value = this.value;
this.callback(); this.callback();
}
}, },
remove() { remove() {
this.duration.value = undefined; this.duration.value = undefined;
}, },
change(value) { change(value) {
if (this.validate()) {
this.$emit('change', value); this.$emit('change', value);
}
}, },
input(value) { input(value) {
this.$emit('input', value); this.$emit('input', value);
},
validate() {
if (Number(this.value) < 0 || this.value=='') {
this.$error(this.$t('commons.formatErr'));
return false;
}
return true;
} }
} }
} }

View File

@ -107,7 +107,7 @@ export default {
jsonPathList.forEach(jsonPath => { jsonPathList.forEach(jsonPath => {
let jsonItem = new JSONPath(); let jsonItem = new JSONPath();
jsonItem.expression = jsonPath.json_path; jsonItem.expression = jsonPath.json_path;
jsonItem.expect = jsonPath.json_value; jsonItem.expect = jsonPath.regular_expression;
jsonItem.setJSONPathDescription(); jsonItem.setJSONPathDescription();
this.assertions.jsonPath.push(jsonItem); this.assertions.jsonPath.push(jsonItem);
}); });

View File

@ -17,10 +17,9 @@
:scenario="scenario" :scenario="scenario"
:extract="extract" :extract="extract"
type="body" type="body"
:description="$t('api_test.request.parameters_desc')"
v-if="body.isKV()"/> v-if="body.isKV()"/>
<div class="body-raw" v-if="body.type == 'Raw'"> <div class="body-raw" v-if="body.type == 'Raw'">
<ms-code-edit :mode="body.format" :read-only="isReadOnly" :data.sync="body.raw" :modes="modes" ref="codeEdit"/> <ms-code-edit :mode="body.format" :enable-format="false" :read-only="isReadOnly" :data.sync="body.raw" :modes="modes" ref="codeEdit"/>
</div> </div>
</div> </div>

View File

@ -3,7 +3,7 @@
<draggable :list="this.scenario.requests" group="Request" class="request-draggable" ghost-class="request-ghost" <draggable :list="this.scenario.requests" group="Request" class="request-draggable" ghost-class="request-ghost"
:disabled="isReference"> :disabled="isReference">
<div class="request-item" v-for="(request, index) in this.scenario.requests" :key="index" @click="select(request)" <div class="request-item" v-for="(request, index) in this.scenario.requests" :key="index" @click="select(request)"
:class="{'selected': isSelected(request), 'disable-request': !request.enable || !scenario.enable}"> :class="{'selected': isSelected(request), 'disable-request': isEnable(request)}">
<ms-condition-label :request="request"/> <ms-condition-label :request="request"/>
<el-row type="flex" align="middle"> <el-row type="flex" align="middle">
<div class="request-type"> <div class="request-type">
@ -180,7 +180,10 @@ export default {
request.dubboConfig = this.scenario.dubboConfig; request.dubboConfig = this.scenario.dubboConfig;
this.selected = request; this.selected = request;
this.$emit("select", request, this.scenario); this.$emit("select", request, this.scenario);
} },
isEnable(request) {
return !request.enable || !this.scenario.isEnable();
},
}, },
created() { created() {

View File

@ -101,7 +101,6 @@ export default {
this.request.debugScenario = new Scenario(); this.request.debugScenario = new Scenario();
this.request.debugRequestResult = {responseResult: {}, subRequestResults: []}; this.request.debugRequestResult = {responseResult: {}, subRequestResults: []};
} }
this.$refs.msDebugResult.reload();
} else { } else {
setTimeout(this.getReport, 2000) setTimeout(this.getReport, 2000)
} }

View File

@ -58,7 +58,11 @@
this.currentConfig = new DatabaseConfig(); this.currentConfig = new DatabaseConfig();
}, },
rowSelect(config) { rowSelect(config) {
//
this.currentConfig = {};
this.$nextTick(() => {
this.currentConfig = config; this.currentConfig = config;
});
} }
} }
} }

View File

@ -80,4 +80,8 @@
float: right; float: right;
} }
.el-table {
cursor: pointer;
}
</style> </style>

View File

@ -29,7 +29,7 @@
</el-form-item> </el-form-item>
<el-form-item :label="$t('api_test.request.sql.pool_max')" prop="poolMax"> <el-form-item :label="$t('api_test.request.sql.pool_max')" prop="poolMax">
<el-input-number size="small" :disabled="isReadOnly" v-model="currentConfig.poolMax" :placeholder="$t('commons.please_select')" :max="1000*10000000" :min="0"/> <el-input-number size="small" :disabled="isReadOnly" v-model="currentConfig.poolMax" :placeholder="$t('commons.please_select')" :max="100" :min="0"/>
</el-form-item> </el-form-item>
@ -39,9 +39,10 @@
<el-form-item> <el-form-item>
<div class="buttons"> <div class="buttons">
<el-button type="primary" v-show="currentConfig.id" size="small" @click="validate()">{{$t('commons.validate')}}</el-button> <el-button type="primary" v-show="currentConfig.id" size="small" @click="validate">{{$t('commons.validate')}}</el-button>
<el-button type="primary" v-show="currentConfig.id" size="small" @click="save('update')">{{$t('commons.update')}}</el-button> <el-button type="primary" v-show="currentConfig.id" size="small" @click="save('update')">{{$t('commons.update')}}</el-button>
<el-button type="primary" size="small" @click="save('add')">{{$t('commons.add')}}</el-button> <el-button type="primary" v-show="currentConfig.id" size="small" @click="clear">{{$t('commons.clear')}}</el-button>
<el-button type="primary" v-show="!currentConfig.id" size="small" @click="save('add')">{{$t('commons.add')}}</el-button>
</div> </div>
</el-form-item> </el-form-item>
@ -127,6 +128,9 @@
} }
}); });
}, },
clear() {
this.currentConfig = new DatabaseConfig();
},
validate() { validate() {
this.result = this.$post('/api/database/validate', this.currentConfig, () => { this.result = this.$post('/api/database/validate', this.currentConfig, () => {
this.$success(this.$t('commons.connection_successful')); this.$success(this.$t('commons.connection_successful'));

View File

@ -230,6 +230,7 @@ export class Scenario extends BaseConfig {
this.databaseConfigs = []; this.databaseConfigs = [];
this.tcpConfig = undefined; this.tcpConfig = undefined;
this.assertions = undefined; this.assertions = undefined;
this.referenceEnable = undefined;
this.set(options); this.set(options);
this.sets({ this.sets({
@ -271,6 +272,14 @@ export class Scenario extends BaseConfig {
isReference() { isReference() {
return this.id.indexOf("#") !== -1 return this.id.indexOf("#") !== -1
} }
isEnable() {
if (this.isReference()) {
return this.referenceEnable;
} else {
return this.enable;
}
}
} }
class DubboConfig extends BaseConfig { class DubboConfig extends BaseConfig {
@ -609,8 +618,8 @@ export class DatabaseConfig extends BaseConfig {
super(); super();
this.id = undefined; this.id = undefined;
this.name = undefined; this.name = undefined;
this.poolMax = undefined; this.poolMax = 1;
this.timeout = undefined; this.timeout = 100000;
this.driver = undefined; this.driver = undefined;
this.dbUrl = undefined; this.dbUrl = undefined;
this.username = undefined; this.username = undefined;
@ -1144,7 +1153,7 @@ class JMXGenerator {
addScenarios(testPlan, testId, scenarios) { addScenarios(testPlan, testId, scenarios) {
scenarios.forEach(s => { scenarios.forEach(s => {
if (s.enable) { if (s.isEnable()) {
let scenario = s.clone(); let scenario = s.clone();
let threadGroup = new ThreadGroup(scenario.name || ""); let threadGroup = new ThreadGroup(scenario.name || "");

View File

@ -28,6 +28,12 @@
init: { init: {
type: Function type: Function
}, },
enableFormat: {
type: Boolean,
default() {
return true;
}
},
readOnly: { readOnly: {
type: Boolean, type: Boolean,
default() { default() {
@ -74,6 +80,7 @@
} }
}, },
format() { format() {
if (this.enableFormat) {
switch (this.mode) { switch (this.mode) {
case 'json': case 'json':
this.formatData = formatJson(this.data); this.formatData = formatJson(this.data);
@ -89,6 +96,9 @@
this.formatData = this.data; this.formatData = this.data;
} }
} }
} else {
this.formatData = this.data;
}
} }
} }
} }

View File

@ -11,6 +11,11 @@
<br/> <br/>
</el-col> </el-col>
</el-row> </el-row>
<el-row class="tip" v-if="withTip">
<span>
<slot class="tip"></slot>
</span>
</el-row>
<el-row> <el-row>
<el-col :span="15"> <el-col :span="15">
<el-input v-model="value" :placeholder="$t('commons.input_content')"/> <el-input v-model="value" :placeholder="$t('commons.input_content')"/>
@ -41,6 +46,12 @@
default() { default() {
return this.$t('commons.title') return this.$t('commons.title')
} }
},
withTip: {
type: Boolean,
default() {
return false
}
} }
}, },
methods: { methods: {
@ -80,5 +91,9 @@
font-weight: bold; font-weight: bold;
} }
.tip {
margin-bottom: 20px;
color: red;
}
</style> </style>

View File

@ -73,7 +73,9 @@
this.$emit('scheduleChange'); this.$emit('scheduleChange');
}, },
flashResultList() { flashResultList() {
if (this.$refs.crontabResult) {
this.$refs.crontabResult.expressionChange(); this.$refs.crontabResult.expressionChange();
}
}, },
cancelRefresh() { cancelRefresh() {
if (this.refreshScheduler) { if (this.refreshScheduler) {

View File

@ -31,7 +31,7 @@
</el-dialog> </el-dialog>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('schedule.task_notification')" name="second"> <el-tab-pane :label="$t('schedule.task_notification')" name="second">
<schedule-task-notification :test-id="testId" :schedule-receiver-options="scheduleReceiverOptions"></schedule-task-notification> <schedule-task-notification :is-tester-permission="isTesterPermission" :test-id="testId" :schedule-receiver-options="scheduleReceiverOptions"></schedule-task-notification>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
@ -46,6 +46,7 @@ import CrontabResult from "../cron/CrontabResult";
import {cronValidate} from "@/common/js/cron"; import {cronValidate} from "@/common/js/cron";
import {listenGoBack, removeGoBackListener} from "@/common/js/utils"; import {listenGoBack, removeGoBackListener} from "@/common/js/utils";
import ScheduleTaskNotification from "../../settings/organization/components/ScheduleTaskNotification"; import ScheduleTaskNotification from "../../settings/organization/components/ScheduleTaskNotification";
import {checkoutTestManagerOrTestUser} from "../../../../common/js/utils";
function defaultCustomValidate() { function defaultCustomValidate() {
return {pass: true}; return {pass: true};
} }
@ -113,10 +114,13 @@ export default {
name: '', name: '',
organizationId: this.currentUser().lastOrganizationId organizationId: this.currentUser().lastOrganizationId
}; };
if (this.isTesterPermission) {
this.result = this.$post('user/org/member/list/all', param, response => { this.result = this.$post('user/org/member/list/all', param, response => {
this.scheduleReceiverOptions = response.data this.scheduleReceiverOptions = response.data
}); });
}
}, },
/* handleClick() { /* handleClick() {
if (this.activeName === "second") { if (this.activeName === "second") {
@ -188,6 +192,11 @@ export default {
let time1 = new Date(resultList[0]); let time1 = new Date(resultList[0]);
let time2 = new Date(resultList[1]); let time2 = new Date(resultList[1]);
return time2 - time1; return time2 - time1;
},
},
computed: {
isTesterPermission() {
return checkoutTestManagerOrTestUser();
} }
} }
} }

View File

@ -9,10 +9,8 @@
</div> </div>
</div> </div>
<div class="report-right"> <div class="report-right">
<div class="test">
<img class="logo" src="@/assets/logo-MeterSphere.png"> <img class="logo" src="@/assets/logo-MeterSphere.png">
</div> </div>
</div>
</div> </div>
</template> </template>

View File

@ -271,12 +271,14 @@ export default {
let reset = this.exportReportReset; let reset = this.exportReportReset;
this.$nextTick(function () { this.$nextTick(function () {
setTimeout(() => {
html2canvas(document.getElementById('performanceReportExport'), { html2canvas(document.getElementById('performanceReportExport'), {
// scale: 2 scale: 2
}).then(function (canvas) { }).then(function (canvas) {
exportPdf(name, [canvas]); exportPdf(name, [canvas]);
reset(); reset();
}); });
}, 1000);
}); });
}, },
exportReportReset() { exportReportReset() {

View File

@ -204,6 +204,7 @@ export default {
}); });
} }
}, },
submit(formName) { submit(formName) {
this.$refs[formName].validate((valid) => { this.$refs[formName].validate((valid) => {
if (valid) { if (valid) {
@ -282,7 +283,18 @@ export default {
}, },
openEnvironmentConfig(project) { openEnvironmentConfig(project) {
this.$refs.environmentConfig.open(project.id); this.$refs.environmentConfig.open(project.id);
},
handleEvent(event) {
if (event.keyCode === 13) {
this.submit('form')
} }
},
},
created() {
document.addEventListener('keydown', this.handleEvent)
},
beforeDestroy() {
document.removeEventListener('keydown', this.handleEvent);
} }
} }
</script> </script>

View File

@ -217,7 +217,7 @@
}) })
}, },
del(row) { del(row) {
this.$confirm(this.$t('member.remove_member'), '', { this.$confirm(this.$t('member.org_remove_member'), '', {
confirmButtonText: this.$t('commons.confirm'), confirmButtonText: this.$t('commons.confirm'),
cancelButtonText: this.$t('commons.cancel'), cancelButtonText: this.$t('commons.cancel'),
type: 'warning' type: 'warning'

View File

@ -145,26 +145,26 @@ export default {
data.isReadOnly = true; data.isReadOnly = true;
if (data.type === 'EMAIL') { if (data.type === 'EMAIL') {
data.isReadOnly = !data.isReadOnly data.isReadOnly = !data.isReadOnly
data.webhook = "" data.webhook = '';
} }
}, },
handleEditTask(index,data) { handleEditTask(index,data) {
data.isSet = true data.isSet = true
if (data.type === 'EMAIL') { if (data.type === 'EMAIL') {
data.isReadOnly = false data.isReadOnly = false;
data.webhook = "" data.webhook = '';
} else { } else {
data.isReadOnly = true data.isReadOnly = true;
} }
}, },
handleAddTaskModel(type) { handleAddTaskModel(type) {
let Task = {}; let Task = {};
Task.event = []; Task.event = [];
Task.userIds = []; Task.userIds = [];
Task.type = ""; Task.type = '';
Task.webhook = ""; Task.webhook = '';
Task.isSet = true; Task.isSet = true;
Task.identification = ""; Task.identification = '';
if (type === 'jenkinsTask') { if (type === 'jenkinsTask') {
Task.taskType = 'JENKINS_TASK' Task.taskType = 'JENKINS_TASK'
this.form.jenkinsTask.push(Task) this.form.jenkinsTask.push(Task)

View File

@ -146,18 +146,18 @@ export default {
handleEdit(index, data) { handleEdit(index, data) {
data.isReadOnly = true; data.isReadOnly = true;
if (data.type === 'EMAIL') { if (data.type === 'EMAIL') {
data.isReadOnly = !data.isReadOnly data.isReadOnly = !data.isReadOnly;
data.webhook = "" data.webhook = '';
} }
}, },
handleAddTaskModel(type) { handleAddTaskModel(type) {
let Task = {}; let Task = {};
Task.event = []; Task.event = [];
Task.userIds = []; Task.userIds = [];
Task.type = ""; Task.type = '';
Task.webhook = ""; Task.webhook = '';
Task.isSet = true; Task.isSet = true;
Task.identification = ""; Task.identification = '';
if (type === 'jenkinsTask') { if (type === 'jenkinsTask') {
Task.taskType = 'JENKINS_TASK' Task.taskType = 'JENKINS_TASK'
this.form.jenkinsTask.push(Task) this.form.jenkinsTask.push(Task)
@ -194,21 +194,20 @@ export default {
handleEditTask(index,data) { handleEditTask(index,data) {
data.isSet = true data.isSet = true
if (data.type === 'EMAIL') { if (data.type === 'EMAIL') {
data.isReadOnly = false data.isReadOnly = false;
data.webhook = "" data.webhook = '';
} else { } else {
data.isReadOnly = true data.isReadOnly = true;
} }
}, },
addTask(data) { addTask(data) {
let list = [] let list = [];
data.isSet = false list.push(data);
list.push(data)
let param = {}; let param = {};
param.messageDetail = list param.messageDetail = list;
this.result = this.$post("/notice/save/message/task", param, () => { this.result = this.$post("/notice/save/message/task", param, () => {
this.initForm() this.initForm();
this.$success(this.$t('commons.save_success')); this.$success(this.$t('commons.save_success'));
}) })
}, },
@ -216,7 +215,7 @@ export default {
if (!data[index].identification) { if (!data[index].identification) {
data.splice(index, 1) data.splice(index, 1)
} else { } else {
data[index].isSet = false data[parseInt(index)].isSet = false;
} }
}, },

View File

@ -2,7 +2,7 @@
<div> <div>
<el-row> <el-row>
<el-col :span="10"> <el-col :span="10">
<el-button icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel('scheduleTask')"> <el-button :disabled="!isTesterPermission" icon="el-icon-circle-plus-outline" plain size="mini" @click="handleAddTaskModel('scheduleTask')">
{{ $t('organization.message.create_new_notification') }} {{ $t('organization.message.create_new_notification') }}
</el-button> </el-button>
</el-col> </el-col>
@ -69,12 +69,14 @@
type="primary" type="primary"
size="mini" size="mini"
v-show="scope.row.isSet" v-show="scope.row.isSet"
:disabled="!isTesterPermission"
@click="handleAddTask(scope.$index,scope.row)" @click="handleAddTask(scope.$index,scope.row)"
>{{ $t('commons.add') }} >{{ $t('commons.add') }}
</el-button> </el-button>
<el-button <el-button
size="mini" size="mini"
v-show="scope.row.isSet" v-show="scope.row.isSet"
:disabled="!isTesterPermission"
@click.native.prevent="removeRowTask(scope.$index,form.scheduleTask)" @click.native.prevent="removeRowTask(scope.$index,form.scheduleTask)"
>{{ $t('commons.cancel') }} >{{ $t('commons.cancel') }}
</el-button> </el-button>
@ -82,6 +84,7 @@
type="primary" type="primary"
size="mini" size="mini"
v-show="!scope.row.isSet" v-show="!scope.row.isSet"
:disabled="!isTesterPermission"
@click="handleEditTask(scope.$index,scope.row)" @click="handleEditTask(scope.$index,scope.row)"
>{{ $t('commons.edit') }}</el-button> >{{ $t('commons.edit') }}</el-button>
<el-button <el-button
@ -89,6 +92,7 @@
icon="el-icon-delete" icon="el-icon-delete"
size="mini" size="mini"
v-show="!scope.row.isSet" v-show="!scope.row.isSet"
:disabled="!isTesterPermission"
@click.native.prevent="deleteRowTask(scope.$index,scope.row)" @click.native.prevent="deleteRowTask(scope.$index,scope.row)"
></el-button> ></el-button>
</template> </template>
@ -106,6 +110,10 @@ export default {
props: { props: {
testId:String, testId:String,
scheduleReceiverOptions:Array, scheduleReceiverOptions:Array,
isTesterPermission: {
type: Boolean,
default: true
}
}, },
data() { data() {
return { return {
@ -120,7 +128,6 @@ export default {
identification: "", identification: "",
isReadOnly: false, isReadOnly: false,
testId:this.testId, testId:this.testId,
}], }],
}, },
scheduleEventOptions: [ scheduleEventOptions: [
@ -147,32 +154,32 @@ export default {
handleEdit(index, data) { handleEdit(index, data) {
data.isReadOnly = true; data.isReadOnly = true;
if (data.type === 'EMAIL') { if (data.type === 'EMAIL') {
data.isReadOnly = !data.isReadOnly data.isReadOnly = !data.isReadOnly;
data.webhook = "" data.webhook = '';
} }
}, },
handleAddTaskModel(type) { handleAddTaskModel(type) {
let Task = {}; let Task = {};
Task.event = []; Task.event = [];
Task.userIds = []; Task.userIds = [];
Task.type = ""; Task.type = '';
Task.webhook = ""; Task.webhook = '';
Task.isSet = true; Task.isSet = true;
Task.identification = ""; Task.identification = '';
if (type === 'scheduleTask') { if (type === 'scheduleTask') {
Task.taskType = 'SCHEDULE_TASK' Task.taskType = 'SCHEDULE_TASK';
Task.testId=this.testId Task.testId=this.testId;
this.form.scheduleTask.push(Task) this.form.scheduleTask.push(Task);
} }
}, },
handleEditTask(index,data) { handleEditTask(index,data) {
data.isSet = true data.isSet = true;
data.testId = this.testId data.testId = this.testId;
if (data.type === 'EMAIL') { if (data.type === 'EMAIL') {
data.isReadOnly = false data.isReadOnly = false;
data.webhook = "" data.webhook = '';
} else { } else {
data.isReadOnly = true data.isReadOnly = true;
} }
}, },
handleAddTask(index, data) { handleAddTask(index, data) {
@ -192,11 +199,10 @@ export default {
} }
}, },
addTask(data) { addTask(data) {
let list = [] let list = [];
data.isSet = false list.push(data);
list.push(data)
let param = {}; let param = {};
param.messageDetail = list param.messageDetail = list;
this.result = this.$post("/notice/save/message/task", param, () => { this.result = this.$post("/notice/save/message/task", param, () => {
this.initForm() this.initForm()
this.$success(this.$t('commons.save_success')); this.$success(this.$t('commons.save_success'));
@ -206,7 +212,7 @@ export default {
if (!data[index].identification) { if (!data[index].identification) {
data.splice(index, 1) data.splice(index, 1)
} else { } else {
data[index].isSet = false data[index].isSet = false;
} }
}, },
deleteRowTask(index, data) { // deleteRowTask(index, data) { //

View File

@ -151,26 +151,26 @@ export default {
data.isReadOnly = true; data.isReadOnly = true;
if (data.type === 'EMAIL') { if (data.type === 'EMAIL') {
data.isReadOnly = !data.isReadOnly data.isReadOnly = !data.isReadOnly
data.webhook = "" data.webhook = '';
} }
}, },
handleEditTask(index,data) { handleEditTask(index,data) {
data.isSet = true data.isSet = true
if (data.type === 'EMAIL') { if (data.type === 'EMAIL') {
data.isReadOnly = false data.isReadOnly = false;
data.webhook = "" data.webhook = '';
} else { } else {
data.isReadOnly = true data.isReadOnly = true;
} }
}, },
handleAddTaskModel(type) { handleAddTaskModel(type) {
let Task = {}; let Task = {};
Task.event = []; Task.event = [];
Task.userIds = []; Task.userIds = [];
Task.type = ""; Task.type = '';
Task.webhook = ""; Task.webhook = '';
Task.isSet = true; Task.isSet = true;
Task.identification = ""; Task.identification = '';
if (type === 'jenkinsTask') { if (type === 'jenkinsTask') {
Task.taskType = 'JENKINS_TASK' Task.taskType = 'JENKINS_TASK'
this.form.jenkinsTask.push(Task) this.form.jenkinsTask.push(Task)

View File

@ -151,27 +151,27 @@ export default {
handleEdit(index, data) { handleEdit(index, data) {
data.isReadOnly = true; data.isReadOnly = true;
if (data.type === 'EMAIL') { if (data.type === 'EMAIL') {
data.isReadOnly = !data.isReadOnly data.isReadOnly = !data.isReadOnly;
data.webhook = "" data.webhook = '';
} }
}, },
handleEditTask(index,data) { handleEditTask(index,data) {
data.isSet = true data.isSet = true;
if (data.type === 'EMAIL') { if (data.type === 'EMAIL') {
data.isReadOnly = false data.isReadOnly = false;
data.webhook = "" data.webhook = '';
} else { } else {
data.isReadOnly = true data.isReadOnly = true;
} }
}, },
handleAddTaskModel(type) { handleAddTaskModel(type) {
let Task = {}; let Task = {};
Task.event = []; Task.event = [];
Task.userIds = []; Task.userIds = [];
Task.type = ""; Task.type = '';
Task.webhook = ""; Task.webhook = '';
Task.isSet = true; Task.isSet = true;
Task.identification = ""; Task.identification = '';
if (type === 'jenkinsTask') { if (type === 'jenkinsTask') {
Task.taskType = 'JENKINS_TASK' Task.taskType = 'JENKINS_TASK'
this.form.jenkinsTask.push(Task) this.form.jenkinsTask.push(Task)
@ -207,13 +207,13 @@ export default {
} }
}, },
addTask(data) { addTask(data) {
let list = [] let list = [];
data.isSet = false data.isSet = false;
list.push(data) list.push(data);
let param = {}; let param = {};
param.messageDetail = list param.messageDetail = list;
this.result = this.$post("/notice/save/message/task", param, () => { this.result = this.$post("/notice/save/message/task", param, () => {
this.initForm() this.initForm();
this.$success(this.$t('commons.save_success')); this.$success(this.$t('commons.save_success'));
}) })
}, },
@ -221,7 +221,7 @@ export default {
if (!data[index].identification) { if (!data[index].identification) {
data.splice(index, 1) data.splice(index, 1)
} else { } else {
data[index].isSet = false data[index].isSet = false;
} }
}, },
deleteRowTask(index, data) { // deleteRowTask(index, data) { //

View File

@ -86,6 +86,7 @@
import MsDialogFooter from "../../common/components/MsDialogFooter"; import MsDialogFooter from "../../common/components/MsDialogFooter";
import {getCurrentUser, listenGoBack, removeGoBackListener} from "../../../../common/js/utils"; import {getCurrentUser, listenGoBack, removeGoBackListener} from "../../../../common/js/utils";
import MsTableOperatorButton from "../../common/components/MsTableOperatorButton"; import MsTableOperatorButton from "../../common/components/MsTableOperatorButton";
import {PHONE_REGEX} from "@/common/js/regex";
export default { export default {
name: "MsPersonSetting", name: "MsPersonSetting",
@ -115,7 +116,7 @@
phone: [ phone: [
{ {
required: false, required: false,
pattern: '^1(3|4|5|7|8)\\d{9}$', pattern: PHONE_REGEX,
message: this.$t('member.mobile_number_format_is_incorrect'), message: this.$t('member.mobile_number_format_is_incorrect'),
trigger: 'blur' trigger: 'blur'
} }

View File

@ -338,6 +338,7 @@ import {hasRole, listenGoBack, removeGoBackListener} from "@/common/js/utils";
import MsRolesTag from "../../common/components/MsRolesTag"; import MsRolesTag from "../../common/components/MsRolesTag";
import {ROLE_ADMIN} from "@/common/js/constants"; import {ROLE_ADMIN} from "@/common/js/constants";
import {getCurrentUser} from "../../../../common/js/utils"; import {getCurrentUser} from "../../../../common/js/utils";
import {PHONE_REGEX} from "@/common/js/regex";
export default { export default {
name: "MsUser", name: "MsUser",
@ -380,7 +381,7 @@ export default {
rule: { rule: {
id: [ id: [
{required: true, message: this.$t('user.input_id'), trigger: 'blur'}, {required: true, message: this.$t('user.input_id'), trigger: 'blur'},
{min: 2, max: 50, message: this.$t('commons.input_limit', [2, 50]), trigger: 'blur'}, {min: 1, max: 50, message: this.$t('commons.input_limit', [1, 50]), trigger: 'blur'},
{ {
required: true, required: true,
pattern: '^[^\u4e00-\u9fa5]+$', pattern: '^[^\u4e00-\u9fa5]+$',
@ -401,7 +402,7 @@ export default {
{required: true, message: this.$t('user.input_phone'), trigger: 'blur'}, {required: true, message: this.$t('user.input_phone'), trigger: 'blur'},
{ {
required: true, required: true,
pattern: '^1(3|4|5|7|8)\\d{9}$', pattern: PHONE_REGEX,
message: this.$t('user.mobile_number_format_is_incorrect'), message: this.$t('user.mobile_number_format_is_incorrect'),
trigger: 'blur' trigger: 'blur'
} }

View File

@ -292,6 +292,8 @@ export default {
}, },
methods: { methods: {
initTableData() { initTableData() {
this.condition.planId = "";
this.condition.nodeIds = [];
if (this.planId) { if (this.planId) {
// param.planId = this.planId; // param.planId = this.planId;
this.condition.planId = this.planId; this.condition.planId = this.planId;
@ -300,6 +302,9 @@ export default {
// param.nodeIds = this.selectNodeIds; // param.nodeIds = this.selectNodeIds;
this.condition.nodeIds = this.selectNodeIds; this.condition.nodeIds = this.selectNodeIds;
} }
this.getData();
},
getData() {
if (this.currentProject) { if (this.currentProject) {
this.condition.projectId = this.currentProject.id; this.condition.projectId = this.currentProject.id;
this.result = this.$post(this.buildPagePath('/test/case/list'), this.condition, response => { this.result = this.$post(this.buildPagePath('/test/case/list'), this.condition, response => {
@ -492,7 +497,6 @@ export default {
}, },
showPopover(row, column, cell) { showPopover(row, column, cell) {
if (column.property === 'name') { if (column.property === 'name') {
console.log(row, column);
this.currentCaseId = row.id; this.currentCaseId = row.id;
} }
} }

View File

@ -85,7 +85,7 @@
}); });
}, },
editTestCase(row, event, column) { editTestCase(row, event, column) {
this.$router.push('/track/plan/view/edit/' + row.caseId) this.$router.push('/track/plan/view/edit/' + row.id)
} }
} }
} }

View File

@ -58,11 +58,8 @@
<el-form-item :label="$t('test_track.plan.plan_stage')" :label-width="formLabelWidth" prop="stage"> <el-form-item :label="$t('test_track.plan.plan_stage')" :label-width="formLabelWidth" prop="stage">
<el-select v-model="form.stage" clearable :placeholder="$t('test_track.plan.input_plan_stage')"> <el-select v-model="form.stage" clearable :placeholder="$t('test_track.plan.input_plan_stage')">
<el-option :label="$t('test_track.plan.smoke_test')" value="smoke"></el-option> <el-option :label="$t('test_track.plan.smoke_test')" value="smoke"></el-option>
<!--<el-option :label="$t('test_track.plan.functional_test')" value="functional"></el-option>-->
<!--<el-option :label="$t('test_track.plan.integration_testing')" value="integration"></el-option>-->
<el-option :label="$t('test_track.plan.system_test')" value="system"></el-option> <el-option :label="$t('test_track.plan.system_test')" value="system"></el-option>
<el-option :label="$t('test_track.plan.regression_test')" value="regression"></el-option> <el-option :label="$t('test_track.plan.regression_test')" value="regression"></el-option>
<!--<el-option :label="$t('test_track.plan.version_validation')" value="version"></el-option>-->
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
@ -196,8 +193,7 @@ export default {
let param = {}; let param = {};
Object.assign(param, this.form); Object.assign(param, this.form);
param.name = param.name.trim(); param.name = param.name.trim();
if (param.name === '') { if (!this.validate(param)) {
this.$warning(this.$t('test_track.plan.input_plan_name'));
return; return;
} }
param.workspaceId = localStorage.getItem(WORKSPACE_ID); param.workspaceId = localStorage.getItem(WORKSPACE_ID);
@ -230,6 +226,17 @@ export default {
} }
}); });
}, },
validate(param) {
if (param.name === '') {
this.$warning(this.$t('test_track.plan.input_plan_name'));
return false;
}
if (param.plannedStartTime > param.plannedEndTime) {
this.$warning(this.$t('commons.date.data_time_error'));
return false;
}
return true;
},
editTestPlan(param) { editTestPlan(param) {
this.$post('/test/plan/' + this.operationType, param, () => { this.$post('/test/plan/' + this.operationType, param, () => {
this.$success(this.$t('commons.save_success')); this.$success(this.$t('commons.save_success'));

View File

@ -137,7 +137,9 @@
<test-report-template-list @openReport="openReport" ref="testReportTemplateList"/> <test-report-template-list @openReport="openReport" ref="testReportTemplateList"/>
<test-case-report-view @refresh="initTableData" ref="testCaseReportView"/> <test-case-report-view @refresh="initTableData" ref="testCaseReportView"/>
<ms-delete-confirm :title="$t('test_track.plan.plan_delete')" @delete="_handleDelete" ref="deleteConfirm"/> <ms-delete-confirm :title="$t('test_track.plan.plan_delete')" @delete="_handleDelete" ref="deleteConfirm" :with-tip="enableDeleteTip">
{{$t('test_track.plan.plan_delete_tip')}}
</ms-delete-confirm>
</el-card> </el-card>
</template> </template>
@ -171,6 +173,7 @@ export default {
data() { data() {
return { return {
result: {}, result: {},
enableDeleteTip: false,
queryPath: "/test/plan/list", queryPath: "/test/plan/list",
deletePath: "/test/plan/delete", deletePath: "/test/plan/delete",
condition: { condition: {
@ -208,11 +211,9 @@ export default {
methods: { methods: {
initTableData() { initTableData() {
if (this.planId) { if (this.planId) {
// param.planId = this.planId;
this.condition.planId = this.planId; this.condition.planId = this.planId;
} }
if (this.selectNodeIds && this.selectNodeIds.length > 0) { if (this.selectNodeIds && this.selectNodeIds.length > 0) {
// param.nodeIds = this.selectNodeIds;
this.condition.nodeIds = this.selectNodeIds; this.condition.nodeIds = this.selectNodeIds;
} }
this.result = this.$post(this.buildPagePath(this.queryPath), this.condition, response => { this.result = this.$post(this.buildPagePath(this.queryPath), this.condition, response => {
@ -251,6 +252,7 @@ export default {
}); });
}, },
handleDelete(testPlan) { handleDelete(testPlan) {
this.enableDeleteTip = testPlan.status === 'Underway' ? true : false;
this.$refs.deleteConfirm.open(testPlan); this.$refs.deleteConfirm.open(testPlan);
}, },
_handleDelete(testPlan) { _handleDelete(testPlan) {

View File

@ -215,6 +215,16 @@
item.checked = false; item.checked = false;
}); });
flag ? this.testCases = tableData : this.testCases = this.testCases.concat(tableData); flag ? this.testCases = tableData : this.testCases = this.testCases.concat(tableData);
//
let hash = {}
this.testCases = this.testCases.reduce((item, next) => {
if (!hash[next.id]) {
hash[next.id] = true
item.push(next)
}
return item
}, [])
this.lineStatus = tableData.length === 50 && this.testCases.length < this.total; this.lineStatus = tableData.length === 50 && this.testCases.length < this.total;
}); });
} }
@ -293,6 +303,8 @@
this.projectId = data[0].id; this.projectId = data[0].id;
this.projectName = data[0].name; this.projectName = data[0].name;
this.search(); this.search();
//
this.getProjectNode(this.projectId)
} }
}) })
} }

View File

@ -93,6 +93,13 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row>
<el-col :span="4" :offset="1" v-if="testCase.testId == 'other'">
<span class="cast_label">{{ $t('test_track.case.test_name') }}</span>
<span class="cast_item">{{ testCase.otherTestName }}</span>
</el-col>
</el-row>
<el-row> <el-row>
<el-col :offset="1"> <el-col :offset="1">
<span class="cast_label">{{ $t('test_track.case.prerequisite') }}</span> <span class="cast_label">{{ $t('test_track.case.prerequisite') }}</span>
@ -100,7 +107,7 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row v-if="testCase.method === 'auto' && testCase.testId"> <el-row v-if="testCase.method === 'auto' && testCase.testId && testCase.testId != 'other'">
<el-col class="test-detail" :span="20" :offset="1"> <el-col class="test-detail" :span="20" :offset="1">
<el-tabs v-model="activeTab" type="border-card" @tab-click="testTabChange"> <el-tabs v-model="activeTab" type="border-card" @tab-click="testTabChange">
<el-tab-pane name="detail" :label="$t('test_track.plan_view.test_detail')"> <el-tab-pane name="detail" :label="$t('test_track.plan_view.test_detail')">

View File

@ -127,7 +127,7 @@
this.listenGoBack(); this.listenGoBack();
}, },
initComponents() { initComponents() {
this.componentMap.forEach((value, key) =>{ this.componentMap.forEach((value, key) => {
if (this.template.content.components.indexOf(key) < 0 && this.components.indexOf(key) < 0) { if (this.template.content.components.indexOf(key) < 0 && this.components.indexOf(key) < 0) {
this.components.push(key); this.components.push(key);
} }
@ -205,7 +205,7 @@
if (this.isReport) { if (this.isReport) {
url = '/case/report/get/'; url = '/case/report/get/';
} }
this.$get(url + id, (response) =>{ this.$get(url + id, (response) => {
this.template = response.data; this.template = response.data;
this.template.content = JSON.parse(response.data.content); this.template.content = JSON.parse(response.data.content);
if (this.template.content.customComponent) { if (this.template.content.customComponent) {
@ -238,7 +238,7 @@
if (this.isReport) { if (this.isReport) {
url = '/case/report/'; url = '/case/report/';
} }
this.$post(url + this.type, param, () =>{ this.$post(url + this.type, param, () => {
this.$success(this.$t('commons.save_success')); this.$success(this.$t('commons.save_success'));
this.handleClose(); this.handleClose();
this.$emit('refresh'); this.$emit('refresh');

View File

@ -210,14 +210,15 @@
let reset = this.exportReportReset; let reset = this.exportReportReset;
this.$nextTick(function () { this.$nextTick(function () {
setTimeout(() => {
html2canvas(document.getElementById('testCaseReportExport'), { html2canvas(document.getElementById('testCaseReportExport'), {
// scale: 2 scale: 2
}).then(function(canvas) { }).then(function(canvas) {
exportPdf(name, [canvas]); exportPdf(name, [canvas]);
reset(); reset();
}); });
}, 1000);
}); });
}, },
exportReportReset() { exportReportReset() {
this.reportExportVisible = false; this.reportExportVisible = false;
@ -225,7 +226,7 @@
}, },
} }
} }
</script> </script>cd
<style scoped> <style scoped>

View File

@ -23,9 +23,10 @@
resize="none" resize="none"
:autosize="{ minRows: 4, maxRows: 4}" :autosize="{ minRows: 4, maxRows: 4}"
@keyup.ctrl.enter.native="sendComment" @keyup.ctrl.enter.native="sendComment"
:disabled="isReadOnly"
> >
</el-input> </el-input>
<el-button type="primary" size="mini" class="send-btn" @click="sendComment"> <el-button type="primary" size="mini" class="send-btn" @click="sendComment" :disabled="isReadOnly">
{{ $t('test_track.comment.send') }} {{ $t('test_track.comment.send') }}
</el-button> </el-button>
</div> </div>
@ -34,6 +35,7 @@
<script> <script>
import ReviewCommentItem from "./ReviewCommentItem"; import ReviewCommentItem from "./ReviewCommentItem";
import {checkoutTestManagerOrTestUser} from "@/common/js/utils";
export default { export default {
name: "ReviewComment", name: "ReviewComment",
@ -47,8 +49,12 @@ export default {
return { return {
result: {}, result: {},
textarea: '', textarea: '',
isReadOnly: false
} }
}, },
created() {
this.isReadOnly = !checkoutTestManagerOrTestUser();
},
methods: { methods: {
sendComment() { sendComment() {
let comment = {}; let comment = {};

View File

@ -129,6 +129,10 @@ export default {
pre { pre {
margin: 0 0; margin: 0 0;
white-space: pre-wrap;
word-wrap: break-word;
width: 100%;
line-height: 20px;
} }
.comment-delete { .comment-delete {

View File

@ -219,6 +219,15 @@
item.checked = false; item.checked = false;
}); });
flag ? this.testReviews = tableData : this.testReviews = this.testReviews.concat(tableData); flag ? this.testReviews = tableData : this.testReviews = this.testReviews.concat(tableData);
//
let hash = {}
this.testReviews = this.testReviews.reduce((item, next) => {
if (!hash[next.id]) {
hash[next.id] = true
item.push(next)
}
return item
}, [])
this.lineStatus = tableData.length === 50 && this.testReviews.length < this.total; this.lineStatus = tableData.length === 50 && this.testReviews.length < this.total;
}); });
@ -231,7 +240,6 @@
this.selectIds.add(item.id); this.selectIds.add(item.id);
}); });
} else { } else {
// this.selectIds.clear();
this.testReviews.forEach(item => { this.testReviews.forEach(item => {
if (this.selectIds.has(item.id)) { if (this.selectIds.has(item.id)) {
this.selectIds.delete(item.id); this.selectIds.delete(item.id);

View File

@ -389,7 +389,7 @@ export default {
this.saveReport(reportId); this.saveReport(reportId);
}, },
saveReport(reportId) { saveReport(reportId) {
// this.$post('/test/plan/case/edit', {id: this.testCase.id, reportId: reportId});
}, },
getComments(testCase) { getComments(testCase) {
let id = ''; let id = '';

View File

@ -301,7 +301,6 @@ export default {
return path + "/" + this.currentPage + "/" + this.pageSize; return path + "/" + this.currentPage + "/" + this.pageSize;
}, },
handleEdit(testCase, index) { handleEdit(testCase, index) {
// console.log(testCase)
this.isReadOnly = false; this.isReadOnly = false;
if (!checkoutTestManagerOrTestUser()) { if (!checkoutTestManagerOrTestUser()) {
this.isReadOnly = true; this.isReadOnly = true;

@ -1 +1 @@
Subproject commit 13907bd5ff621214ae81e42098df382916c503ce Subproject commit 8a972a198775b3783ed6e4cef27197e53d1ebdc8

View File

@ -108,3 +108,9 @@ body {
margin: 5px 0; margin: 5px 0;
border-radius: 5px; border-radius: 5px;
} }
/* 修复带长度限制的文本框,内容太长造成的无法查看内容的问题 */
.el-input__inner[maxlength] {
padding-right: 60px;
}

View File

@ -43,8 +43,10 @@ export default {
success(response.data); success(response.data);
} else { } else {
window.console.warn(response.data); window.console.warn(response.data);
if (response.data.message) {
Message.warning(response.data.message); Message.warning(response.data.message);
} }
}
result.loading = false; result.loading = false;
} }

View File

@ -0,0 +1 @@
export const PHONE_REGEX = '^1(3|4|5|7|8|9)\\d{9}$';

View File

@ -259,3 +259,17 @@ export function exportPdf(name, canvasList) {
} }
export function windowPrint(id, zoom) {
//根据div标签ID拿到div中的局部内容
let bdhtml=window.document.body.innerHTML;
let el = document.getElementById(id);
var jubuData = el.innerHTML;
document.getElementsByTagName('body')[0].style.zoom=zoom;
//把获取的 局部div内容赋给body标签, 相当于重置了 body里的内容
window.document.body.innerHTML= jubuData;
//调用打印功能
window.print();
window.document.body.innerHTML=bdhtml;//重新给页面内容赋值;
return false;
}

View File

@ -314,6 +314,7 @@ export default {
repeat_password: 'Repeat', repeat_password: 'Repeat',
inconsistent_passwords: 'The two passwords entered are inconsistent', 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',
org_remove_member: 'Removing the user from the organization will also remove permissions from all workspaces under the organization. Are you sure you want to remove the 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!',
}, },
@ -836,6 +837,7 @@ export default {
actual_start_time: "Actual Start Time", actual_start_time: "Actual Start Time",
actual_end_time: "Actual End Time", actual_end_time: "Actual End Time",
plan_delete_confirm: "All use cases under this plan will be deleted,confirm delete test plan: ", plan_delete_confirm: "All use cases under this plan will be deleted,confirm delete test plan: ",
plan_delete_tip: "The test plan is under way, please confirm and delete it!",
plan_delete: "Delete test plan", plan_delete: "Delete test plan",
}, },
review: { review: {

Some files were not shown because too many files have changed in this diff Show More