解决冲突
This commit is contained in:
commit
d16839ec68
|
@ -9,4 +9,6 @@ import java.util.List;
|
|||
public interface ExtLoadTestReportMapper {
|
||||
|
||||
List<ReportDTO> getReportList(@Param("reportRequest")ReportRequest request);
|
||||
|
||||
ReportDTO getReportTestAndProInfo(@Param("id") String id);
|
||||
}
|
||||
|
|
|
@ -13,4 +13,12 @@
|
|||
</where>
|
||||
</select>
|
||||
|
||||
<select id="getReportTestAndProInfo" resultType="io.metersphere.dto.ReportDTO">
|
||||
select ltr.id, ltr.name, ltr.test_id as testId, ltr.description,
|
||||
ltr.create_time as createTime, ltr.update_time as updateTime, ltr.status as status, lt.name as testName,
|
||||
p.id as projectId, p.name as projectName
|
||||
from load_test_report ltr join load_test lt on ltr.test_id = lt.id join project p on lt.project_id = p.id
|
||||
where ltr.id = #{id}
|
||||
</select>
|
||||
|
||||
</mapper>
|
|
@ -1,19 +1,27 @@
|
|||
package io.metersphere.controller;
|
||||
|
||||
import io.metersphere.base.domain.UserRole;
|
||||
import io.metersphere.controller.request.LoginRequest;
|
||||
import io.metersphere.dto.UserDTO;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import io.metersphere.user.SessionUtils;
|
||||
import io.metersphere.service.UserService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.authc.*;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequestMapping
|
||||
public class LoginController {
|
||||
|
||||
@Resource
|
||||
private UserService userService;
|
||||
|
||||
@GetMapping(value = "/isLogin")
|
||||
public ResultHolder isLogin() {
|
||||
if (SecurityUtils.getSubject().isAuthenticated()) {
|
||||
|
@ -37,6 +45,20 @@ public class LoginController {
|
|||
try {
|
||||
subject.login(token);
|
||||
if (subject.isAuthenticated()) {
|
||||
UserDTO user = (UserDTO) subject.getSession().getAttribute("user");
|
||||
// 自动选中组织,工作空间
|
||||
if (StringUtils.isBlank(user.getLastOrganizationId())) {
|
||||
List<UserRole> userRoles = user.getUserRoles();
|
||||
List<UserRole> test = userRoles.stream().filter(ur -> ur.getRoleId().indexOf("test") > -1).collect(Collectors.toList());
|
||||
List<UserRole> org = userRoles.stream().filter(ur -> ur.getRoleId().indexOf("org") > -1).collect(Collectors.toList());
|
||||
if (test.size() > 0) {
|
||||
String wsId = test.get(0).getSourceId();
|
||||
userService.switchUserRole(user, "workspace", wsId);
|
||||
} else if (org.size() > 0) {
|
||||
String orgId = org.get(0).getSourceId();
|
||||
userService.switchUserRole(user, "organization", orgId);
|
||||
}
|
||||
}
|
||||
// 返回 userDTO
|
||||
return ResultHolder.success(subject.getSession().getAttribute("user"));
|
||||
} else {
|
||||
|
|
|
@ -37,6 +37,7 @@ public class OrganizationController {
|
|||
}
|
||||
|
||||
@GetMapping("/delete/{organizationId}")
|
||||
@RequiresRoles(RoleConstants.ADMIN)
|
||||
public void deleteOrganization(@PathVariable(value = "organizationId") String organizationId) { organizationService.deleteOrganization(organizationId); }
|
||||
|
||||
@PostMapping("/update")
|
||||
|
|
|
@ -45,4 +45,12 @@ public class ReportController {
|
|||
public void deleteReport(@PathVariable String reportId) {
|
||||
reportService.deleteReport(reportId);
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/test/pro/info/{reportId}")
|
||||
public ReportDTO getReportTestAndProInfo(@PathVariable String reportId) {
|
||||
return reportService.getReportTestAndProInfo(reportId);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package io.metersphere.controller;
|
|||
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import io.metersphere.base.domain.Role;
|
||||
import io.metersphere.base.domain.User;
|
||||
import io.metersphere.commons.constants.RoleConstants;
|
||||
import io.metersphere.commons.utils.PageUtils;
|
||||
|
@ -12,10 +11,10 @@ import io.metersphere.controller.request.member.AddMemberRequest;
|
|||
import io.metersphere.controller.request.member.QueryMemberRequest;
|
||||
import io.metersphere.controller.request.organization.AddOrgMemberRequest;
|
||||
import io.metersphere.controller.request.organization.QueryOrgMemberRequest;
|
||||
import io.metersphere.dto.OrganizationMemberDTO;
|
||||
import io.metersphere.dto.UserDTO;
|
||||
import io.metersphere.dto.UserRoleDTO;
|
||||
import io.metersphere.service.OrganizationService;
|
||||
import io.metersphere.service.UserService;
|
||||
import io.metersphere.service.WorkspaceService;
|
||||
import io.metersphere.user.SessionUser;
|
||||
import io.metersphere.user.SessionUtils;
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
|
@ -31,40 +30,94 @@ public class UserController {
|
|||
|
||||
@Resource
|
||||
private UserService userService;
|
||||
@Resource
|
||||
private OrganizationService organizationService;
|
||||
@Resource
|
||||
private WorkspaceService workspaceService;
|
||||
|
||||
@PostMapping("/add")
|
||||
// admin api
|
||||
@PostMapping("/special/add")
|
||||
@RequiresRoles(RoleConstants.ADMIN)
|
||||
public UserDTO insertUser(@RequestBody User user) {
|
||||
return userService.insert(user);
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
public List<User> getUserList() {
|
||||
return userService.getUserList();
|
||||
}
|
||||
|
||||
@PostMapping("/list/{goPage}/{pageSize}")
|
||||
@PostMapping("/special/list/{goPage}/{pageSize}")
|
||||
@RequiresRoles(RoleConstants.ADMIN)
|
||||
public Pager<List<User>> getUserList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody UserRequest request) {
|
||||
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
|
||||
return PageUtils.setPageInfo(page, userService.getUserListWithRequest(request));
|
||||
}
|
||||
|
||||
@GetMapping("/delete/{userId}")
|
||||
@GetMapping("/special/delete/{userId}")
|
||||
@RequiresRoles(RoleConstants.ADMIN)
|
||||
public void deleteUser(@PathVariable(value = "userId") String userId) {
|
||||
userService.deleteUser(userId);
|
||||
}
|
||||
|
||||
@PostMapping("/update")
|
||||
@PostMapping("/special/update")
|
||||
@RequiresRoles(RoleConstants.ADMIN)
|
||||
public void updateUser(@RequestBody User user) {
|
||||
userService.updateUser(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改登录用户信息
|
||||
*/
|
||||
@PostMapping("/special/ws/member/list/{goPage}/{pageSize}")
|
||||
@RequiresRoles(RoleConstants.ADMIN)
|
||||
public Pager<List<User>> getMemberListByAdmin(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryMemberRequest request) {
|
||||
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
|
||||
return PageUtils.setPageInfo(page, userService.getMemberList(request));
|
||||
}
|
||||
|
||||
@PostMapping("/special/ws/member/list/all")
|
||||
@RequiresRoles(RoleConstants.ADMIN)
|
||||
public List<User> getMemberListByAdmin(@RequestBody QueryMemberRequest request) {
|
||||
return userService.getMemberList(request);
|
||||
}
|
||||
|
||||
@PostMapping("/special/ws/member/add")
|
||||
@RequiresRoles(RoleConstants.ADMIN)
|
||||
public void addMemberByAdmin(@RequestBody AddMemberRequest request) {
|
||||
userService.addMember(request);
|
||||
}
|
||||
|
||||
@GetMapping("/special/ws/member/delete/{workspaceId}/{userId}")
|
||||
@RequiresRoles(RoleConstants.ADMIN)
|
||||
public void deleteMemberByAdmin(@PathVariable String workspaceId, @PathVariable String userId) {
|
||||
userService.deleteMember(workspaceId, userId);
|
||||
}
|
||||
|
||||
@PostMapping("/special/org/member/add")
|
||||
@RequiresRoles(RoleConstants.ADMIN)
|
||||
public void addOrganizationMemberByAdmin(@RequestBody AddOrgMemberRequest request) {
|
||||
userService.addOrganizationMember(request);
|
||||
}
|
||||
|
||||
@GetMapping("/special/org/member/delete/{organizationId}/{userId}")
|
||||
@RequiresRoles(RoleConstants.ADMIN)
|
||||
public void delOrganizationMemberByAdmin(@PathVariable String organizationId, @PathVariable String userId) {
|
||||
userService.delOrganizationMember(organizationId, userId);
|
||||
}
|
||||
|
||||
@PostMapping("/special/org/member/list/{goPage}/{pageSize}")
|
||||
@RequiresRoles(RoleConstants.ADMIN)
|
||||
public Pager<List<User>> getOrgMemberListByAdmin(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryOrgMemberRequest request) {
|
||||
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
|
||||
return PageUtils.setPageInfo(page, userService.getOrgMemberList(request));
|
||||
}
|
||||
|
||||
@PostMapping("/special/org/member/list/all")
|
||||
@RequiresRoles(RoleConstants.ADMIN)
|
||||
public List<User> getOrgMemberListByAdmin(@RequestBody QueryOrgMemberRequest request) {
|
||||
return userService.getOrgMemberList(request);
|
||||
}
|
||||
// admin api
|
||||
|
||||
@GetMapping("/list")
|
||||
@RequiresRoles(value = {RoleConstants.ADMIN,RoleConstants.ORG_ADMIN}, logical = Logical.OR)
|
||||
public List<User> getUserList() {
|
||||
return userService.getUserList();
|
||||
}
|
||||
|
||||
@PostMapping("/update/currentuser")
|
||||
public UserDTO updateCurrentUser(@RequestBody User user) {
|
||||
SessionUser sessionUser = SessionUtils.getUser();
|
||||
|
@ -73,20 +126,19 @@ public class UserController {
|
|||
return SessionUtils.getUser();
|
||||
}
|
||||
|
||||
@GetMapping("/role/list/{userId}")
|
||||
public List<Role> getUserRolesList(@PathVariable(value = "userId") String userId) {
|
||||
return userService.getUserRolesList(userId);
|
||||
}
|
||||
|
||||
@GetMapping("/rolelist/{userId}")
|
||||
public List<UserRoleDTO> convertUserRoleDTO(@PathVariable(value = "userId") String userId) {
|
||||
return userService.getUserRoleList(userId);
|
||||
}
|
||||
|
||||
@PostMapping("/switch/source/{sign}/{sourceId}")
|
||||
public UserDTO switchUserRole(@PathVariable String sign, @PathVariable(value = "sourceId") String sourceId) {
|
||||
@PostMapping("/switch/source/org/{sourceId}")
|
||||
@RequiresRoles(RoleConstants.ORG_ADMIN)
|
||||
public UserDTO switchOrganization(@PathVariable(value = "sourceId") String sourceId) {
|
||||
UserDTO user = SessionUtils.getUser();
|
||||
userService.switchUserRole(user, sign, sourceId);
|
||||
userService.switchUserRole(user,"organization",sourceId);
|
||||
return SessionUtils.getUser();
|
||||
}
|
||||
|
||||
@PostMapping("/switch/source/ws/{sourceId}")
|
||||
@RequiresRoles(value = {RoleConstants.TEST_MANAGER,RoleConstants.TEST_VIEWER,RoleConstants.TEST_USER}, logical = Logical.OR)
|
||||
public UserDTO switchWorkspace(@PathVariable(value = "sourceId") String sourceId) {
|
||||
UserDTO user = SessionUtils.getUser();
|
||||
userService.switchUserRole(user, "workspace", sourceId);
|
||||
return SessionUtils.getUser();
|
||||
}
|
||||
|
||||
|
@ -98,8 +150,9 @@ public class UserController {
|
|||
/**
|
||||
* 获取工作空间成员用户
|
||||
*/
|
||||
@PostMapping("/member/list/{goPage}/{pageSize}")
|
||||
//@RequiresRoles(RoleConstants.TEST_MANAGER)
|
||||
@PostMapping("/ws/member/list/{goPage}/{pageSize}")
|
||||
@RequiresRoles(value = {RoleConstants.ORG_ADMIN,RoleConstants.TEST_MANAGER,
|
||||
RoleConstants.TEST_USER,RoleConstants.TEST_VIEWER}, logical = Logical.OR)
|
||||
public Pager<List<User>> getMemberList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryMemberRequest request) {
|
||||
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
|
||||
return PageUtils.setPageInfo(page, userService.getMemberList(request));
|
||||
|
@ -108,51 +161,59 @@ public class UserController {
|
|||
/**
|
||||
* 获取工作空间成员用户 不分页
|
||||
*/
|
||||
@PostMapping("/member/list/all")
|
||||
@PostMapping("/ws/member/list/all")
|
||||
@RequiresRoles(value = {RoleConstants.ORG_ADMIN,RoleConstants.TEST_MANAGER,
|
||||
RoleConstants.TEST_USER,RoleConstants.TEST_VIEWER}, logical = Logical.OR)
|
||||
public List<User> getMemberList(@RequestBody QueryMemberRequest request) {
|
||||
return userService.getMemberList(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加成员
|
||||
* 添加工作空间成员
|
||||
*/
|
||||
@PostMapping("/member/add")
|
||||
@RequiresRoles(value = {RoleConstants.TEST_MANAGER,RoleConstants.ORG_ADMIN,RoleConstants.ADMIN}, logical = Logical.OR)
|
||||
@PostMapping("/ws/member/add")
|
||||
@RequiresRoles(value = {RoleConstants.TEST_MANAGER,RoleConstants.ORG_ADMIN}, logical = Logical.OR)
|
||||
public void addMember(@RequestBody AddMemberRequest request) {
|
||||
String wsId = request.getWorkspaceId();
|
||||
workspaceService.checkWorkspaceOwner(wsId);
|
||||
userService.addMember(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除成员
|
||||
* 删除工作空间成员
|
||||
*/
|
||||
@GetMapping("/member/delete/{workspaceId}/{userId}")
|
||||
@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.ADMIN, RoleConstants.ORG_ADMIN}, logical = Logical.OR)
|
||||
@GetMapping("/ws/member/delete/{workspaceId}/{userId}")
|
||||
@RequiresRoles(value = {RoleConstants.TEST_MANAGER,RoleConstants.ORG_ADMIN}, logical = Logical.OR)
|
||||
public void deleteMember(@PathVariable String workspaceId, @PathVariable String userId) {
|
||||
workspaceService.checkWorkspaceOwner(workspaceId);
|
||||
userService.deleteMember(workspaceId, userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加组织成员
|
||||
*/
|
||||
@PostMapping("/orgmember/add")
|
||||
@RequiresRoles(value = {RoleConstants.ADMIN, RoleConstants.ORG_ADMIN}, logical = Logical.OR)
|
||||
@PostMapping("/org/member/add")
|
||||
@RequiresRoles(RoleConstants.ORG_ADMIN)
|
||||
public void addOrganizationMember(@RequestBody AddOrgMemberRequest request) {
|
||||
organizationService.checkOrgOwner(request.getOrganizationId());
|
||||
userService.addOrganizationMember(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除组织成员
|
||||
*/
|
||||
@GetMapping("/orgmember/delete/{organizationId}/{userId}")
|
||||
@RequiresRoles(value = {RoleConstants.ADMIN,RoleConstants.ORG_ADMIN}, logical = Logical.OR)
|
||||
@GetMapping("/org/member/delete/{organizationId}/{userId}")
|
||||
@RequiresRoles(RoleConstants.ORG_ADMIN)
|
||||
public void delOrganizationMember(@PathVariable String organizationId, @PathVariable String userId) {
|
||||
organizationService.checkOrgOwner(organizationId);
|
||||
userService.delOrganizationMember(organizationId, userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询组织成员列表
|
||||
*/
|
||||
@PostMapping("/orgmember/list/{goPage}/{pageSize}")
|
||||
@PostMapping("/org/member/list/{goPage}/{pageSize}")
|
||||
@RequiresRoles(value = {RoleConstants.ORG_ADMIN,RoleConstants.TEST_MANAGER}, logical = Logical.OR)
|
||||
public Pager<List<User>> getOrgMemberList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryOrgMemberRequest request) {
|
||||
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
|
||||
return PageUtils.setPageInfo(page, userService.getOrgMemberList(request));
|
||||
|
@ -161,23 +222,12 @@ public class UserController {
|
|||
/**
|
||||
* 组织成员列表不分页
|
||||
*/
|
||||
@PostMapping("/orgmember/list/all")
|
||||
@PostMapping("/org/member/list/all")
|
||||
@RequiresRoles(value = {RoleConstants.ORG_ADMIN,RoleConstants.TEST_MANAGER}, logical = Logical.OR)
|
||||
public List<User> getOrgMemberList(@RequestBody QueryOrgMemberRequest request) {
|
||||
return userService.getOrgMemberList(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询组织成员列表 带角色信息
|
||||
*/
|
||||
@PostMapping("/orgmemberdto/list/{goPage}/{pageSize}")
|
||||
public Pager<List<OrganizationMemberDTO>> getOrganizationMemberDTO(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryOrgMemberRequest request) {
|
||||
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
|
||||
return PageUtils.setPageInfo(page, userService.getOrganizationMemberDTO(request));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@GetMapping("/besideorg/list/{orgId}")
|
||||
public List<User> getBesideOrgMemberList(@PathVariable String orgId) {
|
||||
return userService.getBesideOrgMemberList(orgId);
|
||||
|
|
|
@ -26,6 +26,7 @@ public class UserRoleController {
|
|||
}
|
||||
|
||||
@GetMapping("/list/ws/{workspaceId}/{userId}")
|
||||
@RequiresRoles(value = {RoleConstants.ADMIN,RoleConstants.ORG_ADMIN}, logical = Logical.OR)
|
||||
public List<Role> getWorkspaceMemberRole(@PathVariable String workspaceId, @PathVariable String userId) {
|
||||
return userRoleService.getWorkspaceMemberRoles(workspaceId, userId);
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ public class WorkspaceController {
|
|||
@PostMapping("update")
|
||||
@RequiresRoles(RoleConstants.ORG_ADMIN)
|
||||
public Workspace updateWorkspace(@RequestBody Workspace workspace) {
|
||||
workspaceService.checkOwner(workspace.getId());
|
||||
workspaceService.checkWorkspaceOwnerByOrgAdmin(workspace.getId());
|
||||
return workspaceService.saveWorkspace(workspace);
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ public class WorkspaceController {
|
|||
@GetMapping("delete/{workspaceId}")
|
||||
@RequiresRoles(RoleConstants.ORG_ADMIN)
|
||||
public void deleteWorkspace(@PathVariable String workspaceId) {
|
||||
workspaceService.checkOwner(workspaceId);
|
||||
workspaceService.checkWorkspaceOwnerByOrgAdmin(workspaceId);
|
||||
workspaceService.deleteWorkspace(workspaceId);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,24 @@ public class ReportDTO {
|
|||
private String status;
|
||||
private String content;
|
||||
private String testName;
|
||||
private String projectId;
|
||||
private String projectName;
|
||||
|
||||
public String getProjectId() {
|
||||
return projectId;
|
||||
}
|
||||
|
||||
public void setProjectId(String projectId) {
|
||||
this.projectId = projectId;
|
||||
}
|
||||
|
||||
public String getProjectName() {
|
||||
return projectName;
|
||||
}
|
||||
|
||||
public void setProjectName(String projectName) {
|
||||
this.projectName = projectName;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
|
|
|
@ -4,18 +4,11 @@ import io.metersphere.base.domain.*;
|
|||
import io.metersphere.base.mapper.FileContentMapper;
|
||||
import io.metersphere.base.mapper.FileMetadataMapper;
|
||||
import io.metersphere.base.mapper.LoadTestFileMapper;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
|
@ -27,17 +20,6 @@ public class FileService {
|
|||
@Resource
|
||||
private FileContentMapper fileContentMapper;
|
||||
|
||||
// 将上传的文件保存在内存,方便测试
|
||||
private Map<String, MultipartFile> fileMap = new ConcurrentHashMap<>();
|
||||
|
||||
public void upload(String name, MultipartFile file) throws IOException {
|
||||
String result = new BufferedReader(new InputStreamReader(file.getInputStream()))
|
||||
.lines().collect(Collectors.joining("\n"));
|
||||
System.out.println(String.format("upload file: %s, content: \n%s", name, result));
|
||||
|
||||
fileMap.put(name, file);
|
||||
}
|
||||
|
||||
public byte[] loadFileAsBytes(String id) {
|
||||
FileContent fileContent = fileContentMapper.selectByPrimaryKey(id);
|
||||
|
||||
|
|
|
@ -6,8 +6,13 @@ import io.metersphere.base.mapper.UserMapper;
|
|||
import io.metersphere.base.mapper.UserRoleMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtOrganizationMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtUserRoleMapper;
|
||||
import io.metersphere.commons.constants.RoleConstants;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.dto.OrganizationMemberDTO;
|
||||
import io.metersphere.dto.UserRoleHelpDTO;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import io.metersphere.user.SessionUser;
|
||||
import io.metersphere.user.SessionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
@ -109,4 +114,16 @@ public class OrganizationService {
|
|||
public Integer checkSourceRole(String orgId, String userId, String roleId) {
|
||||
return extOrganizationMapper.checkSourceRole(orgId, userId, roleId);
|
||||
}
|
||||
|
||||
public void checkOrgOwner(String organizationId) {
|
||||
SessionUser user = SessionUtils.getUser();
|
||||
List<String> collect = user.getUserRoles().stream()
|
||||
.filter(ur -> RoleConstants.ORG_ADMIN.equals(ur.getRoleId()))
|
||||
.map(UserRole::getSourceId)
|
||||
.collect(Collectors.toList());
|
||||
if (!collect.contains(organizationId)) {
|
||||
MSException.throwException(Translator.get("organization_does_not_belong_to_user"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,4 +37,8 @@ public class ReportService {
|
|||
public void deleteReport(String reportId) {
|
||||
loadTestReportMapper.deleteByPrimaryKey(reportId);
|
||||
}
|
||||
|
||||
public ReportDTO getReportTestAndProInfo(String reportId) {
|
||||
return extLoadTestReportMapper.getReportTestAndProInfo(reportId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ public class UserService {
|
|||
userMapper.updateByPrimaryKeySelective(user);
|
||||
}
|
||||
|
||||
public List<Role> getUserRolesList(String userId) {
|
||||
/*public List<Role> getUserRolesList(String userId) {
|
||||
UserRoleExample userRoleExample = new UserRoleExample();
|
||||
userRoleExample.createCriteria().andUserIdEqualTo(userId);
|
||||
List<UserRole> userRolesList = userRoleMapper.selectByExample(userRoleExample);
|
||||
|
@ -143,7 +143,7 @@ public class UserService {
|
|||
return new ArrayList<>();
|
||||
}
|
||||
return convertUserRoleDTO(extUserRoleMapper.getUserRoleHelpList(userId));
|
||||
}
|
||||
}*/
|
||||
|
||||
private List<UserRoleDTO> convertUserRoleDTO(List<UserRoleHelpDTO> helpDTOList) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
|
|
|
@ -91,15 +91,16 @@ public class WorkspaceService {
|
|||
}
|
||||
|
||||
/**
|
||||
* ORG_ADMIN 需要检查是否有操作此工作空间的权限
|
||||
* ORG_ADMIN需要检查是否有操作此工作空间的权限
|
||||
*/
|
||||
public void checkOwner(String workspaceId) {
|
||||
public void checkWorkspaceOwnerByOrgAdmin(String workspaceId) {
|
||||
checkWorkspaceIsExist(workspaceId);
|
||||
WorkspaceExample example = new WorkspaceExample();
|
||||
SessionUser user = SessionUtils.getUser();
|
||||
List<String> orgIds = user.getUserRoles().stream()
|
||||
.filter(ur -> RoleConstants.ORG_ADMIN.equals(ur.getRoleId()))
|
||||
.map(UserRole::getSourceId)
|
||||
.collect(Collectors.toList());
|
||||
WorkspaceExample example = new WorkspaceExample();
|
||||
example.createCriteria()
|
||||
.andOrganizationIdIn(orgIds)
|
||||
.andIdEqualTo(workspaceId);
|
||||
|
@ -108,6 +109,48 @@ public class WorkspaceService {
|
|||
}
|
||||
}
|
||||
|
||||
public void checkWorkspaceOwnerByTestManager(String workspaceId) {
|
||||
checkWorkspaceIsExist(workspaceId);
|
||||
SessionUser user = SessionUtils.getUser();
|
||||
List<String> wsIds = user.getUserRoles().stream()
|
||||
.filter(ur -> RoleConstants.TEST_MANAGER.equals(ur.getRoleId()))
|
||||
.map(UserRole::getSourceId)
|
||||
.collect(Collectors.toList());
|
||||
boolean contains = wsIds.contains(workspaceId);
|
||||
if (!contains) {
|
||||
MSException.throwException(Translator.get("workspace_does_not_belong_to_user"));
|
||||
}
|
||||
}
|
||||
|
||||
public void checkWorkspaceOwner(String workspaceId) {
|
||||
checkWorkspaceIsExist(workspaceId);
|
||||
WorkspaceExample example = new WorkspaceExample();
|
||||
SessionUser user = SessionUtils.getUser();
|
||||
List<String> orgIds = user.getUserRoles().stream()
|
||||
.filter(ur -> RoleConstants.ORG_ADMIN.equals(ur.getRoleId()))
|
||||
.map(UserRole::getSourceId)
|
||||
.collect(Collectors.toList());
|
||||
example.createCriteria()
|
||||
.andOrganizationIdIn(orgIds)
|
||||
.andIdEqualTo(workspaceId);
|
||||
List<String> wsIds = user.getUserRoles().stream()
|
||||
.filter(ur -> RoleConstants.TEST_MANAGER.equals(ur.getRoleId()))
|
||||
.map(UserRole::getSourceId)
|
||||
.collect(Collectors.toList());
|
||||
boolean contains = wsIds.contains(workspaceId);
|
||||
if (workspaceMapper.countByExample(example) == 0 && !contains) {
|
||||
MSException.throwException(Translator.get("workspace_does_not_belong_to_user"));
|
||||
}
|
||||
}
|
||||
|
||||
public void checkWorkspaceIsExist(String workspaceId) {
|
||||
WorkspaceExample example = new WorkspaceExample();
|
||||
example.createCriteria().andIdEqualTo(workspaceId);
|
||||
if (workspaceMapper.countByExample(example) == 0) {
|
||||
MSException.throwException("workspace_not_exist");
|
||||
}
|
||||
}
|
||||
|
||||
public List<Workspace> getWorkspaceListByUserId(String userId) {
|
||||
List<UserRoleHelpDTO> userRoleHelpList = extUserRoleMapper.getUserRoleHelpList(userId);
|
||||
List<String> workspaceIds = new ArrayList<>();
|
||||
|
|
|
@ -5,5 +5,6 @@
|
|||
"project_name_already_exists": "The project name already exists",
|
||||
"workspace_name_is_null": "Workspace name cannot be null",
|
||||
"workspace_name_already_exists": "The workspace name already exists",
|
||||
"workspace_does_not_belong_to_user": "The current workspace does not belong to the current user"
|
||||
"workspace_does_not_belong_to_user": "The current workspace does not belong to the current user",
|
||||
"organization_does_not_belong_to_user": "The current organization does not belong to the current user"
|
||||
}
|
|
@ -5,5 +5,6 @@
|
|||
"project_name_already_exists": "项目名称已存在",
|
||||
"workspace_name_is_null": "工作空间名不能为空",
|
||||
"workspace_name_already_exists": "工作空间名已存在",
|
||||
"workspace_does_not_belong_to_user": "当前工作空间不属于当前用户"
|
||||
"workspace_does_not_belong_to_user": "当前工作空间不属于当前用户",
|
||||
"organization_does_not_belong_to_user": "当前组织不属于当前用户"
|
||||
}
|
|
@ -40,7 +40,9 @@
|
|||
"plugin:vue/essential",
|
||||
"eslint:recommended"
|
||||
],
|
||||
"rules": {},
|
||||
"rules": {
|
||||
"vue/no-unused-components": "off"
|
||||
},
|
||||
"parserOptions": {
|
||||
"parser": "babel-eslint"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import {ROLE_ORG_ADMIN, ROLE_TEST_MANAGER, ROLE_TEST_USER, ROLE_TEST_VIEWER, TokenKey} from "./constants";
|
||||
|
||||
export function hasRole(role) {
|
||||
let user = JSON.parse(localStorage.getItem(TokenKey));
|
||||
let roles = user.roles.map(r => r.id);
|
||||
return roles.indexOf(role) > -1;
|
||||
}
|
||||
|
||||
export function hasRoles(...roles) {
|
||||
let user = JSON.parse(localStorage.getItem(TokenKey));
|
||||
let rs = user.roles.map(r => r.id);
|
||||
for (let item of roles) {
|
||||
if (rs.indexOf(item) > -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function checkoutCurrentOrganization() {
|
||||
let user = JSON.parse(localStorage.getItem(TokenKey));
|
||||
// 查看当前用户是否是 lastOrganizationId 的组织管理员
|
||||
return user.userRoles.filter(ur => hasRole(ROLE_ORG_ADMIN) && user.lastOrganizationId === ur.sourceId).length > 0;
|
||||
}
|
||||
|
||||
export function checkoutCurrentWorkspace() {
|
||||
let user = JSON.parse(localStorage.getItem(TokenKey));
|
||||
// 查看当前用户是否是 lastWorkspaceId 的工作空间用户
|
||||
return user.userRoles.filter(ur => hasRoles(ROLE_TEST_MANAGER, ROLE_TEST_USER, ROLE_TEST_VIEWER) && user.lastWorkspaceId === ur.sourceId).length > 0;
|
||||
}
|
|
@ -33,6 +33,13 @@ export default {
|
|||
'status': 'Enable/Disable',
|
||||
'show_all': 'Show All',
|
||||
'report': 'Report',
|
||||
'user': 'User',
|
||||
'system': 'System',
|
||||
'personal_setting': 'Personal Setting',
|
||||
'test_resource_pool': 'Resource Pool',
|
||||
'system_setting': 'Settings',
|
||||
'functional': 'Functional',
|
||||
'performance': 'Performance',
|
||||
},
|
||||
workspace: {
|
||||
'create': 'Create Workspace',
|
||||
|
@ -71,6 +78,7 @@ export default {
|
|||
'search_by_name': 'Search by name',
|
||||
'modify_personal_info': 'Modify Personal Information',
|
||||
'input_name': 'Please enter a user name',
|
||||
'input_email': 'Please enter a email',
|
||||
'special_characters_are_not_supported': 'Special characters are not supported',
|
||||
'mobile_number_format_is_incorrect': 'Mobile number format is incorrect',
|
||||
'email_format_is_incorrect': 'Email format is incorrect',
|
||||
|
@ -93,6 +101,10 @@ export default {
|
|||
'recent': 'Recent Report',
|
||||
'search_by_name': 'Search by Name',
|
||||
'test_name': 'Test',
|
||||
'test_overview': 'Test Overview',
|
||||
'test_request_statistics': 'Test Request Statistics',
|
||||
'test_error_log': 'Test Error Log',
|
||||
'test_log_details': 'Test Log Details'
|
||||
},
|
||||
load_test: {
|
||||
'recent': 'Recent Tests',
|
||||
|
|
|
@ -33,6 +33,13 @@ export default {
|
|||
'status': '启用/禁用',
|
||||
'show_all': '显示全部',
|
||||
'report': '报告',
|
||||
'user': '用户',
|
||||
'system': '系统',
|
||||
'personal_setting': '个人设置',
|
||||
'test_resource_pool': '测试资源池',
|
||||
'system_setting': '系统设置',
|
||||
'functional': '功能测试',
|
||||
'performance': '性能测试',
|
||||
},
|
||||
workspace: {
|
||||
'create': '创建工作空间',
|
||||
|
@ -94,6 +101,10 @@ export default {
|
|||
'recent': '最近的报告',
|
||||
'search_by_name': '根据名称搜索',
|
||||
'test_name': '所属测试',
|
||||
'test_overview': '测试概览',
|
||||
'test_request_statistics': '请求统计',
|
||||
'test_error_log': '错误记录',
|
||||
'test_log_details': '日志详情'
|
||||
},
|
||||
load_test: {
|
||||
'recent': '最近的测试',
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
<ms-user/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<ms-view/>
|
||||
<ms-web-socket/>
|
||||
</el-col>
|
||||
|
@ -26,7 +27,7 @@
|
|||
name: 'app',
|
||||
data() {
|
||||
return {
|
||||
auth: false,
|
||||
auth: false
|
||||
}
|
||||
},
|
||||
beforeCreate() {
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
<el-menu-item :index="'/' + beaseUrl + '/home'">
|
||||
{{ $t("i18n.home") }}
|
||||
</el-menu-item>
|
||||
<el-submenu index="3" popper-class="submenu" v-permission="['test_manager']">
|
||||
|
||||
<el-submenu index="3" popper-class="submenu" v-permission="['test_manager']" v-if="isCurrentWorkspaceUser">
|
||||
<template slot="title">{{$t('commons.project')}}</template>
|
||||
<ms-recent-project/>
|
||||
<performance-recent-project v-if="beaseUrl == 'performance'"/>
|
||||
<functional-recent-project v-if="beaseUrl == 'functional'"/>
|
||||
<el-divider/>
|
||||
<el-menu-item :index="'/' + beaseUrl + '/project/all'">
|
||||
<font-awesome-icon :icon="['fa', 'list-ul']"/>
|
||||
|
@ -18,7 +20,9 @@
|
|||
<el-button type="text">{{$t('project.create')}}</el-button>
|
||||
</el-menu-item>
|
||||
</el-submenu>
|
||||
<el-submenu index="4" popper-class="submenu" v-permission="['test_manager', 'test_user']">
|
||||
|
||||
<el-submenu index="4" popper-class="submenu" v-permission="['test_manager', 'test_user']"
|
||||
v-if="isCurrentWorkspaceUser">
|
||||
<template slot="title">{{$t('commons.test')}}</template>
|
||||
<performance-recent-test-plan v-if="beaseUrl == 'performance'"/>
|
||||
<functional-recent-test-plan v-if="beaseUrl == 'functional'"/>
|
||||
|
@ -31,7 +35,9 @@
|
|||
<el-button type="text">{{$t('load_test.create')}}</el-button>
|
||||
</el-menu-item>
|
||||
</el-submenu>
|
||||
<el-submenu index="5" popper-class="submenu" v-permission="['test_manager', 'test_user', 'test_viewer']">
|
||||
|
||||
<el-submenu index="5" popper-class="submenu" v-permission="['test_manager', 'test_user', 'test_viewer']"
|
||||
v-if="isCurrentWorkspaceUser">
|
||||
<template slot="title">{{$t('commons.report')}}</template>
|
||||
<performance-recent-report v-if="beaseUrl == 'performance'"/>
|
||||
<functional-recent-report v-if="beaseUrl == 'functional'"/>
|
||||
|
@ -41,9 +47,12 @@
|
|||
<span style="padding-left: 5px;">{{$t('commons.show_all')}}</span>
|
||||
</el-menu-item>
|
||||
</el-submenu>
|
||||
<router-link class="header-bottom" :to="'/' + beaseUrl + '/plan/create'" v-permission="['test_user','test_manager']">
|
||||
|
||||
<router-link class="header-bottom" :to="'/' + beaseUrl + '/plan/create'" v-permission="['test_user','test_manager']"
|
||||
v-if="isCurrentWorkspaceUser">
|
||||
<el-button type="primary" size="small">{{$t('load_test.create')}}</el-button>
|
||||
</router-link>
|
||||
|
||||
</el-menu>
|
||||
</div>
|
||||
|
||||
|
@ -53,19 +62,31 @@
|
|||
|
||||
import PerformanceRecentTestPlan from "./testPlan/PerformanceRecentTestPlan";
|
||||
import FunctionalRecentTestPlan from "./testPlan/FunctionalRecentTestPlan";
|
||||
import MsRecentProject from "./project/RecentProject";
|
||||
import PerformanceRecentProject from "./project/PerformanceRecentProject";
|
||||
import FunctionalRecentProject from "./project/FunctionalRecentProject";
|
||||
import PerformanceRecentReport from "./report/PerformanceRecentReport";
|
||||
import FunctionalRecentReport from "./report/FunctionalRecentReport";
|
||||
import {checkoutCurrentWorkspace} from "../../common/utils";
|
||||
|
||||
export default {
|
||||
name: "MsMenus",
|
||||
components: {PerformanceRecentReport, PerformanceRecentTestPlan, MsRecentProject, FunctionalRecentTestPlan, FunctionalRecentReport},
|
||||
props: {
|
||||
beaseUrl: {
|
||||
type: String
|
||||
components: {PerformanceRecentReport, PerformanceRecentTestPlan, FunctionalRecentTestPlan, FunctionalRecentReport,
|
||||
PerformanceRecentProject,FunctionalRecentProject},
|
||||
data() {
|
||||
return {
|
||||
isCurrentWorkspaceUser: false,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
beaseUrl: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.isCurrentWorkspaceUser = checkoutCurrentWorkspace();
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
<template>
|
||||
<el-row class="settings" type="flex" justify="end" align="middle">
|
||||
<router-link to="/content">
|
||||
<font-awesome-icon :icon="['fas', 'user-plus']" size="lg"/>
|
||||
</router-link>
|
||||
<router-link to="/setting">
|
||||
<font-awesome-icon :icon="['fas', 'cog']" size="lg"/>
|
||||
</router-link>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsSetting"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.settings > * {
|
||||
padding-left: 15px;
|
||||
cursor: pointer;
|
||||
line-height: 40px;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.settings > * :hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.settings > * :active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
</style>
|
|
@ -7,14 +7,17 @@
|
|||
:default-active="activeIndex"
|
||||
@select="handleSelect"
|
||||
router>
|
||||
|
||||
<el-menu-item index="/functional" v-permission="['test_manager','test_user','test_viewer']">
|
||||
功能测试
|
||||
{{$t('commons.functional')}}
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/performance" onselectstart="return false"
|
||||
v-permission="['test_manager','test_user','test_viewer']">
|
||||
性能测试
|
||||
{{$t('commons.performance')}}
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/setting/personsetting" onselectstart="return false">
|
||||
{{$t('commons.system_setting')}}
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/setting/personsetting" onselectstart="return false">系统设置</el-menu-item>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -42,7 +42,8 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {ROLE_TEST_MANAGER, ROLE_TEST_USER, ROLE_TEST_VIEWER, TokenKey} from '../../common/constants';
|
||||
import {ROLE_ORG_ADMIN, ROLE_TEST_MANAGER, ROLE_TEST_USER, ROLE_TEST_VIEWER, TokenKey} from '../../common/constants';
|
||||
import {hasRoles} from "../../common/utils";
|
||||
|
||||
export default {
|
||||
name: "MsUser",
|
||||
|
@ -89,18 +90,17 @@
|
|||
}
|
||||
},
|
||||
initMenuData() {
|
||||
let roles = this.currentUser.roles.map(r => r.id);
|
||||
// if (roles.indexOf(ROLE_ORG_ADMIN) > -1) {
|
||||
this.$get("/organization/list/userorg/" + this.currentUserId, response => {
|
||||
let data = response.data;
|
||||
this.organizationList = data;
|
||||
let org = data.filter(r => r.id === this.currentUser.lastOrganizationId);
|
||||
if (org.length > 0) {
|
||||
this.currentOrganizationName = org[0].name;
|
||||
}
|
||||
});
|
||||
// }
|
||||
if (roles.indexOf(ROLE_TEST_MANAGER) > -1 || roles.indexOf(ROLE_TEST_USER) > -1 || roles.indexOf(ROLE_TEST_VIEWER) > -1) {
|
||||
if (hasRoles(ROLE_ORG_ADMIN, ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {
|
||||
this.$get("/organization/list/userorg/" + this.currentUserId, response => {
|
||||
let data = response.data;
|
||||
this.organizationList = data;
|
||||
let org = data.filter(r => r.id === this.currentUser.lastOrganizationId);
|
||||
if (org.length > 0) {
|
||||
this.currentOrganizationName = org[0].name;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {
|
||||
if (!this.currentUser.lastOrganizationId) {
|
||||
return false;
|
||||
}
|
||||
|
@ -126,19 +126,17 @@
|
|||
},
|
||||
changeOrg(data) {
|
||||
let orgId = data.id;
|
||||
let sign = "organization";
|
||||
this.$post("/user/switch/source/" + sign + "/" + orgId, {}, response => {
|
||||
this.$post("/user/switch/source/org/" + orgId, {}, response => {
|
||||
localStorage.setItem(TokenKey, JSON.stringify(response.data));
|
||||
window.location.reload();
|
||||
})
|
||||
},
|
||||
changeWs(data) {
|
||||
let sign = "workspace";
|
||||
let workspaceId = data.id;
|
||||
if (!workspaceId) {
|
||||
return false;
|
||||
}
|
||||
this.$post("/user/switch/source/" + sign + "/" + workspaceId, {}, response => {
|
||||
this.$post("/user/switch/source/ws/" + workspaceId, {}, response => {
|
||||
localStorage.setItem(TokenKey, JSON.stringify(response.data));
|
||||
window.location.reload();
|
||||
})
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
</div>
|
||||
|
||||
<el-menu-item :key="p.id" v-for="p in recentProjects"
|
||||
:index="'/loadtest/' + p.id" :route="{name:'loadtest', params:{projectId:p.id, projectName:p.name}}">
|
||||
:index="'/functional/' + p.id" :route="{name:'fucPlan', params:{projectId:p.id, projectName:p.name}}">
|
||||
{{ p.name }}
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
|
@ -15,14 +15,13 @@
|
|||
<script>
|
||||
|
||||
import {ROLE_TEST_MANAGER, ROLE_TEST_USER, ROLE_TEST_VIEWER} from "../../../common/constants";
|
||||
import {hasRoles} from "../../../common/utils";
|
||||
|
||||
export default {
|
||||
name: "MsRecentProject",
|
||||
name: "FunctionalRecentProject",
|
||||
mounted() {
|
||||
const rolesString = localStorage.getItem("roles");
|
||||
const roles = rolesString.split(',');
|
||||
|
||||
if (roles.indexOf(ROLE_TEST_MANAGER) > -1 || roles.indexOf(ROLE_TEST_USER) > -1 || roles.indexOf(ROLE_TEST_VIEWER) > -1) {
|
||||
if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {
|
||||
this.$get('/project/recent/5', (response) => {
|
||||
this.recentProjects = response.data;
|
||||
});
|
|
@ -90,18 +90,23 @@
|
|||
},
|
||||
}
|
||||
},
|
||||
props: {
|
||||
beaseUrl: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.$route.path.split('/')[2] === 'create') {
|
||||
if (this.$route.path.split('/')[3] === 'create') {
|
||||
this.create();
|
||||
this.$router.push('/project/all');
|
||||
this.$router.push( '/' + this.beaseUrl + '/project/all');
|
||||
}
|
||||
this.list();
|
||||
},
|
||||
watch: {
|
||||
'$route'(to) {
|
||||
if (to.path.split('/')[2] === 'create') {
|
||||
if (to.path.split('/')[3] === 'create') {
|
||||
this.create();
|
||||
this.$router.push('/project/all');
|
||||
this.$router.push('/' + this.beaseUrl + '/project/all');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,14 +1,193 @@
|
|||
<template>
|
||||
<div>
|
||||
功能测试图表
|
||||
</div>
|
||||
<chart :options="bar"></chart>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import echarts from 'echarts'
|
||||
|
||||
export default {
|
||||
name: "PerformanceChart"
|
||||
name: "PerformanceChart",
|
||||
data() {
|
||||
return {
|
||||
bar: {
|
||||
|
||||
backgroundColor: '#394056',
|
||||
title: {
|
||||
top: 20,
|
||||
text: 'Requests',
|
||||
textStyle: {
|
||||
fontWeight: 'normal',
|
||||
fontSize: 16,
|
||||
color: '#F1F1F3'
|
||||
},
|
||||
left: '1%'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
lineStyle: {
|
||||
color: '#57617B'
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
top: 20,
|
||||
icon: 'rect',
|
||||
itemWidth: 14,
|
||||
itemHeight: 5,
|
||||
itemGap: 13,
|
||||
data: ['CMCC', 'CTCC', 'CUCC'],
|
||||
right: '4%',
|
||||
textStyle: {
|
||||
fontSize: 12,
|
||||
color: '#F1F1F3'
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
top: 100,
|
||||
left: '2%',
|
||||
right: '2%',
|
||||
bottom: '2%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: [{
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#57617B'
|
||||
}
|
||||
},
|
||||
data: ['13:00', '13:05', '13:10', '13:15', '13:20', '13:25', '13:30', '13:35', '13:40', '13:45', '13:50', '13:55']
|
||||
}],
|
||||
yAxis: [{
|
||||
type: 'value',
|
||||
name: '(%)',
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#57617B'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
margin: 10,
|
||||
textStyle: {
|
||||
fontSize: 14
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#57617B'
|
||||
}
|
||||
}
|
||||
}],
|
||||
series: [{
|
||||
name: 'CMCC',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbol: 'circle',
|
||||
symbolSize: 5,
|
||||
showSymbol: false,
|
||||
lineStyle: {
|
||||
normal: {
|
||||
width: 1
|
||||
}
|
||||
},
|
||||
areaStyle: {
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
|
||||
offset: 0,
|
||||
color: 'rgba(137, 189, 27, 0.3)'
|
||||
}, {
|
||||
offset: 0.8,
|
||||
color: 'rgba(137, 189, 27, 0)'
|
||||
}], false),
|
||||
shadowColor: 'rgba(0, 0, 0, 0.1)',
|
||||
shadowBlur: 10
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: 'rgb(137,189,27)',
|
||||
borderColor: 'rgba(137,189,2,0.27)',
|
||||
borderWidth: 12
|
||||
|
||||
}
|
||||
},
|
||||
data: [220, 182, 191, 134, 150, 120, 110, 125, 145, 122, 165, 122]
|
||||
}, {
|
||||
name: 'CTCC',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbol: 'circle',
|
||||
symbolSize: 5,
|
||||
showSymbol: false,
|
||||
lineStyle: {
|
||||
normal: {
|
||||
width: 1
|
||||
}
|
||||
},
|
||||
areaStyle: {
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
|
||||
offset: 0,
|
||||
color: 'rgba(0, 136, 212, 0.3)'
|
||||
}, {
|
||||
offset: 0.8,
|
||||
color: 'rgba(0, 136, 212, 0)'
|
||||
}], false),
|
||||
shadowColor: 'rgba(0, 0, 0, 0.1)',
|
||||
shadowBlur: 10
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: 'rgb(0,136,212)',
|
||||
borderColor: 'rgba(0,136,212,0.2)',
|
||||
borderWidth: 12
|
||||
|
||||
}
|
||||
},
|
||||
data: [120, 110, 125, 145, 122, 165, 122, 220, 182, 191, 134, 150]
|
||||
}, {
|
||||
name: 'CUCC',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbol: 'circle',
|
||||
symbolSize: 5,
|
||||
showSymbol: false,
|
||||
lineStyle: {
|
||||
normal: {
|
||||
width: 1
|
||||
}
|
||||
},
|
||||
areaStyle: {
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
|
||||
offset: 0,
|
||||
color: 'rgba(219, 50, 51, 0.3)'
|
||||
}, {
|
||||
offset: 0.8,
|
||||
color: 'rgba(219, 50, 51, 0)'
|
||||
}], false),
|
||||
shadowColor: 'rgba(0, 0, 0, 0.1)',
|
||||
shadowBlur: 10
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: 'rgb(219,50,51)',
|
||||
borderColor: 'rgba(219,50,51,0.2)',
|
||||
borderWidth: 12
|
||||
}
|
||||
},
|
||||
data: [220, 182, 125, 145, 122, 191, 134, 150, 120, 110, 165, 122]
|
||||
}]
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
<template>
|
||||
<el-menu router menu-trigger="click" :default-active="$route.path">
|
||||
<div class="recent-text">
|
||||
<i class="el-icon-time"/>
|
||||
{{$t('project.recent')}}
|
||||
</div>
|
||||
|
||||
<el-menu-item :key="p.id" v-for="p in recentProjects"
|
||||
:index="'/performance/plan/' + p.id" :route="{name:'perPlan', params:{projectId:p.id, projectName:p.name}}">
|
||||
{{ p.name }}
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import {ROLE_TEST_MANAGER, ROLE_TEST_USER, ROLE_TEST_VIEWER} from "../../../common/constants";
|
||||
import {hasRoles} from "../../../common/utils";
|
||||
|
||||
export default {
|
||||
name: "PerformanceRecentProject",
|
||||
mounted() {
|
||||
|
||||
if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {
|
||||
this.$get('/project/recent/5', (response) => {
|
||||
this.recentProjects = response.data;
|
||||
});
|
||||
}
|
||||
},
|
||||
methods: {},
|
||||
data() {
|
||||
return {
|
||||
recentProjects: [],
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.recent-text {
|
||||
padding-left: 10%;
|
||||
color: #777777;
|
||||
}
|
||||
</style>
|
|
@ -5,7 +5,7 @@
|
|||
{{$t('load_test.recent')}}
|
||||
</div>
|
||||
<el-menu-item :key="p.id" v-for="p in recentReports"
|
||||
:index="'/report/' + p.id" :route="{name:'report', params:{projectId:p.id, projectName:p.name}}">
|
||||
:index="'/functional/report/view/' + p.id" :route="{path: '/functional/report/view/' + p.id}">
|
||||
{{ p.name }}
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
<span class="title">{{$t('commons.report')}}</span>
|
||||
<span class="search">
|
||||
<el-input type="text" size="small" :placeholder="$t('report.search_by_name')"
|
||||
prefix-icon="el-icon-search"
|
||||
maxlength="60"
|
||||
v-model="condition" @change="search" clearable/>
|
||||
prefix-icon="el-icon-search"
|
||||
maxlength="60"
|
||||
v-model="condition" @change="search" clearable/>
|
||||
</span>
|
||||
</el-row>
|
||||
</div>
|
||||
|
@ -129,8 +129,10 @@
|
|||
handleSelectionChange(val) {
|
||||
this.multipleSelection = val;
|
||||
},
|
||||
handleEdit() {
|
||||
|
||||
handleEdit(report) {
|
||||
this.$router.push({
|
||||
path: '/functional/reportView/' + report.id
|
||||
})
|
||||
},
|
||||
handleDelete(report) {
|
||||
this.$alert(this.$t('load_test.delete_confirm') + report.name + "?", '', {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
{{$t('load_test.recent')}}
|
||||
</div>
|
||||
<el-menu-item :key="p.id" v-for="p in recentReports"
|
||||
:index="'/report/' + p.id" :route="{name:'report', params:{projectId:p.id, projectName:p.name}}">
|
||||
:index="'/performance/report/view/' + p.id" :route="{path: '/performance/report/view/' + p.id}">
|
||||
{{ p.name }}
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
|
@ -13,14 +13,13 @@
|
|||
|
||||
<script>
|
||||
import {ROLE_TEST_MANAGER, ROLE_TEST_USER, ROLE_TEST_VIEWER} from "../../../common/constants";
|
||||
import {hasRoles} from "../../../common/utils";
|
||||
|
||||
export default {
|
||||
name: "PerformanceRecentReport",
|
||||
mounted() {
|
||||
const rolesString = localStorage.getItem("roles");
|
||||
const roles = rolesString.split(',');
|
||||
|
||||
if (roles.indexOf(ROLE_TEST_MANAGER) > -1 || roles.indexOf(ROLE_TEST_USER) > -1 || roles.indexOf(ROLE_TEST_VIEWER) > -1) {
|
||||
if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {
|
||||
this.$get('/report/recent/5', (response) => {
|
||||
this.recentReports = response.data;
|
||||
});
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
<template>
|
||||
<div v-loading="result.loading" class="report-view-container">
|
||||
<div class="main-content">
|
||||
<el-card>
|
||||
<el-row>
|
||||
<el-col :span="16">
|
||||
<el-row>
|
||||
<el-breadcrumb separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb-item :to="{ path: '/' }">{{projectName}}</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>{{testName}}</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>{{reportName}}</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
</el-row>
|
||||
<el-row class="ms-report-view-btns">
|
||||
<el-button type="primary" plain size="mini">立即停止</el-button>
|
||||
<el-button type="success" plain size="mini">再次执行</el-button>
|
||||
<el-button type="info" plain size="mini">导出</el-button>
|
||||
<el-button type="warning" plain size="mini">比较</el-button>
|
||||
</el-row>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<span class="ms-report-time-desc">
|
||||
持续时间: 30 分钟
|
||||
</span>
|
||||
<span class="ms-report-time-desc">
|
||||
开始时间: 2020-3-10 12:00:00
|
||||
</span>
|
||||
<span class="ms-report-time-desc">
|
||||
结束时间: 2020-3-10 12:30:00
|
||||
</span>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-divider></el-divider>
|
||||
|
||||
<el-tabs v-model="active" type="border-card" :stretch="true">
|
||||
<el-tab-pane :label="$t('report.test_overview')">
|
||||
<ms-report-test-overview />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('report.test_request_statistics')">
|
||||
<ms-report-request-statistics />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('report.test_error_log')">
|
||||
<ms-report-error-log />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('report.test_log_details')">
|
||||
<ms-report-log-details />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsReportErrorLog from './components/ErrorLog';
|
||||
import MsReportLogDetails from './components/LogDetails';
|
||||
import MsReportRequestStatistics from './components/RequestStatistics';
|
||||
import MsReportTestOverview from './components/TestOverview';
|
||||
|
||||
export default {
|
||||
name: "PerformanceReportView",
|
||||
components: {
|
||||
MsReportErrorLog,
|
||||
MsReportLogDetails,
|
||||
MsReportRequestStatistics,
|
||||
MsReportTestOverview
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
active: '0',
|
||||
reportId: '',
|
||||
reportName: '',
|
||||
testName: '',
|
||||
projectName: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initBreadcrumb() {
|
||||
if(this.reportId){
|
||||
this.result = this.$get("report/test/pro/info/" + this.reportId, res => {
|
||||
let data = res.data;
|
||||
if(data){
|
||||
this.reportName = data.name;
|
||||
this.testName = data.testName;
|
||||
this.projectName = data.projectName;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.reportId = this.$route.path.split('/')[4];
|
||||
this.initBreadcrumb();
|
||||
},
|
||||
watch: {
|
||||
'$route'(to) {
|
||||
let reportId = to.path.split('/')[4];
|
||||
if(reportId){
|
||||
this.$get("report/test/pro/info/" + reportId, response => {
|
||||
let data = response.data;
|
||||
if(data){
|
||||
this.reportName = data.name;
|
||||
this.testName = data.testName;
|
||||
this.projectName = data.projectName;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.report-view-container {
|
||||
float: none;
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.report-view-container .main-content {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
max-width: 1200px;
|
||||
}
|
||||
|
||||
.ms-report-view-btns {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.ms-report-time-desc {
|
||||
text-align: left;
|
||||
display: block;
|
||||
color: #5C7878;
|
||||
}
|
||||
</style>
|
|
@ -129,8 +129,10 @@
|
|||
handleSelectionChange(val) {
|
||||
this.multipleSelection = val;
|
||||
},
|
||||
handleEdit() {
|
||||
|
||||
handleEdit(report) {
|
||||
this.$router.push({
|
||||
path: '/performance/report/view/' + report.id
|
||||
})
|
||||
},
|
||||
handleDelete(report) {
|
||||
this.$alert(this.$t('load_test.delete_confirm') + report.name + "?", '', {
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-table
|
||||
:data="tableData"
|
||||
border
|
||||
style="width: 100%"
|
||||
:default-sort = "{prop: 'elementLabel'}"
|
||||
>
|
||||
<el-table-column
|
||||
prop="typeOfError"
|
||||
label="Type of Error"
|
||||
sortable>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="numberOfErrors"
|
||||
label="Number of errors"
|
||||
sortable>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="error"
|
||||
label="% in errors"
|
||||
sortable>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="allSamples"
|
||||
label="% in all samples"
|
||||
sortable>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "ErrorLog",
|
||||
data() {
|
||||
return {
|
||||
tableData: [{},{},{},{},{}]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,15 @@
|
|||
<template>
|
||||
<div>
|
||||
LogDetails
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "LogDetails"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,97 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-table
|
||||
:data="tableData"
|
||||
border
|
||||
style="width: 100%"
|
||||
:default-sort = "{prop: 'elementLabel'}"
|
||||
>
|
||||
<el-table-column
|
||||
prop="elementLabel"
|
||||
label="Element Label"
|
||||
fixed
|
||||
width="150"
|
||||
sortable>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="samples"
|
||||
label="Samples"
|
||||
width="150"
|
||||
sortable>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="avgResponseTime"
|
||||
label="Avg Response Time(ms)"
|
||||
width="220"
|
||||
sortable>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="avgHits"
|
||||
label="Avg Hits/s"
|
||||
width="150"
|
||||
sortable>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="90line"
|
||||
label="90% line(ms)"
|
||||
width="150"
|
||||
sortable>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="95line"
|
||||
label="95% line(ms)"
|
||||
width="150"
|
||||
sortable>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="99line"
|
||||
label="99% line(ms)"
|
||||
width="150"
|
||||
sortable>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="minResponseTime"
|
||||
label="Min Response Time(ms)"
|
||||
width="220"
|
||||
sortable>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="maxResponseTime"
|
||||
label="Max Response Time(ms)"
|
||||
width="220"
|
||||
sortable>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="avgBandwidth"
|
||||
label="Avg Bandwidth(KBytes/s)"
|
||||
width="220"
|
||||
sortable>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="errorPercentage"
|
||||
label="Error Percentage"
|
||||
width="180"
|
||||
fixed="right"
|
||||
sortable>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "RequestStatistics",
|
||||
data() {
|
||||
return {
|
||||
tableData: [{},{},{},{},{}]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,229 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="4">
|
||||
<el-card shadow="always" class="ms-card-index-1">
|
||||
<span class="ms-card-data">
|
||||
<span class="ms-card-data-digital">40</span>
|
||||
<span class="ms-card-data-unit"> VU</span>
|
||||
</span>
|
||||
<span class="ms-card-desc">Max Users</span>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-card shadow="always" class="ms-card-index-2">
|
||||
<span class="ms-card-data">
|
||||
<span class="ms-card-data-digital">5.4</span>
|
||||
<span class="ms-card-data-unit"> Hits/s</span>
|
||||
</span>
|
||||
<span class="ms-card-desc">Avg.Throughput</span>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-card shadow="always" class="ms-card-index-3">
|
||||
<span class="ms-card-data">
|
||||
<span class="ms-card-data-digital">0.41</span>
|
||||
<span class="ms-card-data-unit"> %</span>
|
||||
</span>
|
||||
<span class="ms-card-desc">Errors</span>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-card shadow="always" class="ms-card-index-4">
|
||||
<span class="ms-card-data">
|
||||
<span class="ms-card-data-digital">1.28</span>
|
||||
<span class="ms-card-data-unit"> s</span>
|
||||
</span>
|
||||
<span class="ms-card-desc">Avg.Response Time</span>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-card shadow="always" class="ms-card-index-5">
|
||||
<span class="ms-card-data">
|
||||
<span class="ms-card-data-digital">1.41</span>
|
||||
<span class="ms-card-data-unit"> s</span>
|
||||
</span>
|
||||
<span class="ms-card-desc">90% Response Time</span>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-card shadow="always" class="ms-card-index-6">
|
||||
<span class="ms-card-data">
|
||||
<span class="ms-card-data-digital">817.29</span>
|
||||
<span class="ms-card-data-unit"> KiB/s</span>
|
||||
</span>
|
||||
<span class="ms-card-desc">Avg.Bandwidth</span>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<chart ref="chart1" :options="option1" :autoresize="true"></chart>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<chart ref="chart2" :options="option2" :autoresize="true"></chart>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "TestOverview",
|
||||
data() {
|
||||
return {
|
||||
option1: {
|
||||
legend: {
|
||||
top: 20,
|
||||
data: ['Users', 'Hits/s', 'Error(s)']
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['12:40', '12:50', '13:00', '13:10', '13:20', '13:30', '13:40']
|
||||
},
|
||||
yAxis: [{
|
||||
name: 'User',
|
||||
type: 'value',
|
||||
},
|
||||
{
|
||||
name: 'Hits/s',
|
||||
type: 'value'
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: 'Users',
|
||||
color: '#0CA74A',
|
||||
data: [20, 40, 40, 40, 40, 40, 40],
|
||||
type: 'line',
|
||||
},
|
||||
{
|
||||
name: 'Hits/s',
|
||||
color: '#65A2FF',
|
||||
data: [15, 38, 35, 39, 36, 37, 5],
|
||||
type: 'line',
|
||||
},
|
||||
{
|
||||
name: 'Error(s)',
|
||||
color: '#E6113C',
|
||||
data: [0, 0, 0, 0, 0, 0, 0],
|
||||
type: 'line',
|
||||
}
|
||||
]
|
||||
},
|
||||
option2: {
|
||||
legend: {
|
||||
top: 20,
|
||||
data: ['Users', 'Response Time']
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['12:40', '12:50', '13:00', '13:10', '13:20', '13:30', '13:40']
|
||||
},
|
||||
yAxis: [{
|
||||
name: 'User',
|
||||
type: 'value',
|
||||
},
|
||||
{
|
||||
name: 'Response Time',
|
||||
type: 'value'
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: 'Users',
|
||||
color: '#0CA74A',
|
||||
data: [20, 40, 40, 40, 40, 40, 40],
|
||||
type: 'line',
|
||||
},
|
||||
{
|
||||
name: 'Response Time',
|
||||
color: '#99743C',
|
||||
data: [15, 38, 35, 39, 36, 37, 5],
|
||||
type: 'line',
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.ms-card-data {
|
||||
text-align: left;
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.ms-card-desc {
|
||||
display: block;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.ms-card-data-digital {
|
||||
font-size: 21px;
|
||||
}
|
||||
|
||||
.ms-card-data-unit {
|
||||
color: #8492a6;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.ms-card-index-1 .ms-card-data-digital {
|
||||
color: #44b349;
|
||||
}
|
||||
|
||||
.ms-card-index-1 {
|
||||
border-left-color: #44b349;
|
||||
border-left-width: 3px;
|
||||
}
|
||||
|
||||
.ms-card-index-2 .ms-card-data-digital {
|
||||
color: #65A2FF;
|
||||
}
|
||||
|
||||
.ms-card-index-2 {
|
||||
border-left-color: #65A2FF;
|
||||
border-left-width: 3px;
|
||||
}
|
||||
|
||||
.ms-card-index-3 .ms-card-data-digital {
|
||||
color: #E6113C;
|
||||
}
|
||||
|
||||
.ms-card-index-3 {
|
||||
border-left-color: #E6113C;
|
||||
border-left-width: 3px;
|
||||
}
|
||||
|
||||
.ms-card-index-4 .ms-card-data-digital {
|
||||
color: #99743C;
|
||||
}
|
||||
|
||||
.ms-card-index-4 {
|
||||
border-left-color: #99743C;
|
||||
border-left-width: 3px;
|
||||
}
|
||||
|
||||
.ms-card-index-5 .ms-card-data-digital {
|
||||
color: #99743C;
|
||||
}
|
||||
|
||||
.ms-card-index-5 {
|
||||
border-left-color: #99743C;
|
||||
border-left-width: 3px;
|
||||
}
|
||||
|
||||
.ms-card-index-6 .ms-card-data-digital {
|
||||
color: #3C9899;
|
||||
}
|
||||
|
||||
.ms-card-index-6 {
|
||||
border-left-color: #3C9899;
|
||||
border-left-width: 3px;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -22,6 +22,7 @@ import EditFunctionalTestPlan from "../testPlan/EditFunctionalTestPlan";
|
|||
import PerformanceTestHome from "../testPlan/PerformanceTestHome";
|
||||
import FunctionalTestPlan from "../testPlan/FunctionalTestPlan";
|
||||
import FunctionalTestHome from "../testPlan/FunctionalTestHome";
|
||||
import PerformanceReportView from "../report/PerformanceReportView";
|
||||
|
||||
Vue.use(VueRouter);
|
||||
|
||||
|
@ -84,6 +85,7 @@ const router = new VueRouter({
|
|||
children: [
|
||||
{
|
||||
path: 'home',
|
||||
name: 'fucHome',
|
||||
component: FunctionalTestHome,
|
||||
},
|
||||
{
|
||||
|
@ -93,6 +95,7 @@ const router = new VueRouter({
|
|||
},
|
||||
{
|
||||
path: "plan/edit/:testId",
|
||||
name: "editFucTest",
|
||||
component: EditFunctionalTestPlan,
|
||||
props: {
|
||||
content: (route) => {
|
||||
|
@ -104,14 +107,17 @@ const router = new VueRouter({
|
|||
},
|
||||
{
|
||||
path: "plan/:projectId",
|
||||
name: "fucPlan",
|
||||
component: FunctionalTestPlan
|
||||
},
|
||||
{
|
||||
path: "project/:type",
|
||||
name: "fucProject",
|
||||
component: MsProject
|
||||
},
|
||||
{
|
||||
path: "report/:type",
|
||||
name: "fucReport",
|
||||
component: FunctionalTestReport
|
||||
}
|
||||
]
|
||||
|
@ -126,6 +132,7 @@ const router = new VueRouter({
|
|||
children: [
|
||||
{
|
||||
path: 'home',
|
||||
name: 'perHome',
|
||||
component: PerformanceTestHome,
|
||||
},
|
||||
{
|
||||
|
@ -135,6 +142,7 @@ const router = new VueRouter({
|
|||
},
|
||||
{
|
||||
path: "plan/edit/:testId",
|
||||
name: "editPerTest",
|
||||
component: EditPerformanceTestPlan,
|
||||
props: {
|
||||
content: (route) => {
|
||||
|
@ -146,19 +154,28 @@ const router = new VueRouter({
|
|||
},
|
||||
{
|
||||
path: "plan/:projectId",
|
||||
name: "perPlan",
|
||||
component: PerformanceTestPlan
|
||||
},
|
||||
{
|
||||
path: "project/:type",
|
||||
name: "perProject",
|
||||
component: MsProject
|
||||
},
|
||||
{
|
||||
path: "report/:type",
|
||||
name: "perReport",
|
||||
component: PerformanceTestReport
|
||||
},
|
||||
{
|
||||
path: "chart",
|
||||
name: "perChart",
|
||||
component: PerformanceChart
|
||||
},
|
||||
{
|
||||
path: "report/view/:reportId",
|
||||
name: "perReportView",
|
||||
component: PerformanceReportView
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -3,45 +3,59 @@
|
|||
<el-submenu index="1" v-permission="['admin']">
|
||||
<template slot="title">
|
||||
<font-awesome-icon class="icon account" :icon="['far', 'address-card']" size="lg"/>
|
||||
<span>系统</span>
|
||||
<span>{{$t('commons.system')}}</span>
|
||||
</template>
|
||||
<el-menu-item index="/setting/user">用户</el-menu-item>
|
||||
<el-menu-item index="/setting/organization">组织</el-menu-item>
|
||||
<el-menu-item index="/setting/systemworkspace">工作空间</el-menu-item>
|
||||
<el-menu-item index="/setting/testresourcepool">测试资源池</el-menu-item>
|
||||
<el-menu-item index="/setting/user">{{$t('commons.user')}}</el-menu-item>
|
||||
<el-menu-item index="/setting/organization">{{$t('commons.organization')}}</el-menu-item>
|
||||
<el-menu-item index="/setting/systemworkspace">{{$t('commons.workspace')}}</el-menu-item>
|
||||
<el-menu-item index="/setting/testresourcepool">{{$t('commons.test_resource_pool')}}</el-menu-item>
|
||||
</el-submenu>
|
||||
|
||||
<el-submenu index="2" v-permission="['org_admin']">
|
||||
<el-submenu index="2" v-permission="['org_admin']" v-if="isCurrentOrganizationAdmin">
|
||||
<template slot="title">
|
||||
<font-awesome-icon class="icon organization" :icon="['far', 'building']" size="lg"/>
|
||||
<span>组织</span>
|
||||
<span>{{$t('commons.organization')}}</span>
|
||||
</template>
|
||||
<el-menu-item index="/setting/organizationmember" v-permission="['org_admin']">成员</el-menu-item>
|
||||
<el-menu-item index="/setting/organizationworkspace" v-permission="['org_admin']">工作空间</el-menu-item>
|
||||
<el-menu-item index="/setting/organizationmember" v-permission="['org_admin']">{{$t('commons.member')}}
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/setting/organizationworkspace" v-permission="['org_admin']">{{$t('commons.workspace')}}
|
||||
</el-menu-item>
|
||||
</el-submenu>
|
||||
|
||||
<el-submenu index="3" v-permission="['test_manager','test_user','test_viewer']">
|
||||
<el-submenu index="3" v-permission="['test_manager','test_user','test_viewer']" v-if="isCurrentWorkspaceUser">
|
||||
<template slot="title">
|
||||
<font-awesome-icon class="icon workspace" :icon="['far', 'list-alt']" size="lg"/>
|
||||
<span>工作空间</span>
|
||||
<span>{{$t('commons.workspace')}}</span>
|
||||
</template>
|
||||
<el-menu-item index="/setting/member">成员</el-menu-item>
|
||||
<el-menu-item index="/setting/member">{{$t('commons.member')}}</el-menu-item>
|
||||
</el-submenu>
|
||||
|
||||
<el-submenu index="4">
|
||||
<template slot="title">
|
||||
<font-awesome-icon class="icon" :icon="['far', 'user']" size="lg"/>
|
||||
<span>个人</span>
|
||||
<span>{{$t('commons.personal_info')}}</span>
|
||||
</template>
|
||||
<el-menu-item index="/setting/personsetting">个人设置</el-menu-item>
|
||||
<el-menu-item index="/setting/personsetting">{{$t('commons.personal_setting')}}</el-menu-item>
|
||||
</el-submenu>
|
||||
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {checkoutCurrentOrganization, checkoutCurrentWorkspace} from "../../../common/utils";
|
||||
|
||||
export default {
|
||||
name: "MsSettingMenu"
|
||||
name: "MsSettingMenu",
|
||||
data() {
|
||||
return {
|
||||
isCurrentOrganizationAdmin: false,
|
||||
isCurrentWorkspaceUser: false,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.isCurrentOrganizationAdmin = checkoutCurrentOrganization();
|
||||
this.isCurrentWorkspaceUser = checkoutCurrentWorkspace();
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@
|
|||
createVisible: false,
|
||||
updateVisible: false,
|
||||
form: {},
|
||||
queryPath: "/user/orgmember/list",
|
||||
queryPath: "/user/org/member/list",
|
||||
condition: "",
|
||||
tableData: [],
|
||||
rules: {
|
||||
|
@ -221,7 +221,7 @@
|
|||
cancelButtonText: this.$t('commons.cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.result = this.$get('/user/orgmember/delete/' + this.currentUser().lastOrganizationId + '/' + row.id, () => {
|
||||
this.result = this.$get('/user/org/member/delete/' + this.currentUser().lastOrganizationId + '/' + row.id, () => {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: this.$t('commons.delete_success')
|
||||
|
@ -262,7 +262,7 @@
|
|||
roleIds: this.form.roleIds,
|
||||
organizationId: orgId
|
||||
};
|
||||
this.result = this.$post("user/orgmember/add", param,() => {
|
||||
this.result = this.$post("user/org/member/add", param,() => {
|
||||
this.initTableData();
|
||||
this.createVisible = false;
|
||||
})
|
||||
|
|
|
@ -256,7 +256,7 @@
|
|||
name: '',
|
||||
workspaceId: this.items[i].id
|
||||
}
|
||||
let path = "user/member/list/all";
|
||||
let path = "user/ws/member/list/all";
|
||||
this.$post(path, param, res => {
|
||||
let member = res.data;
|
||||
this.$set(this.items[i], "memberSize", member.length);
|
||||
|
@ -297,7 +297,7 @@
|
|||
name: '',
|
||||
workspaceId: row.id
|
||||
};
|
||||
let path = "/user/member/list";
|
||||
let path = "/user/ws/member/list";
|
||||
this.result = this.$post(this.buildPagePath(path), param, res => {
|
||||
let data = res.data;
|
||||
this.memberLineData = data.listObject;
|
||||
|
@ -335,7 +335,7 @@
|
|||
roleIds: this.memberForm.roleIds,
|
||||
workspaceId: this.currentWorkspaceRow.id
|
||||
};
|
||||
this.result = this.$post("user/member/add", param,() => {
|
||||
this.result = this.$post("user/ws/member/add", param,() => {
|
||||
this.cellClick(this.currentWorkspaceRow);
|
||||
this.addMemberVisible = false;
|
||||
})
|
||||
|
@ -360,7 +360,7 @@
|
|||
cancelButtonText: this.$t('commons.cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.result = this.$get('/user/member/delete/' + this.currentWorkspaceRow.id + '/' + row.id, () => {
|
||||
this.result = this.$get('/user/ws/member/delete/' + this.currentWorkspaceRow.id + '/' + row.id, () => {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: this.$t('commons.delete_success')
|
||||
|
|
|
@ -290,7 +290,7 @@
|
|||
name: '',
|
||||
organizationId: row.id
|
||||
};
|
||||
let path = "/user/orgmember/list";
|
||||
let path = "/user/special/org/member/list";
|
||||
this.result = this.$post(this.buildPagePath(path), param, res => {
|
||||
let data = res.data;
|
||||
this.memberLineData = data.listObject;
|
||||
|
@ -330,7 +330,7 @@
|
|||
cancelButtonText: this.$t('commons.cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.result = this.$get('/user/orgmember/delete/' + this.currentRow.id + '/' + row.id, () => {
|
||||
this.result = this.$get('/user/special/org/member/delete/' + this.currentRow.id + '/' + row.id, () => {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: this.$t('commons.delete_success')
|
||||
|
@ -385,7 +385,7 @@
|
|||
name: '',
|
||||
organizationId: this.tableData[i].id
|
||||
}
|
||||
let path = "user/orgmember/list/all";
|
||||
let path = "user/special/org/member/list/all";
|
||||
this.$post(path, param, res => {
|
||||
let member = res.data;
|
||||
this.$set(this.tableData[i], "memberSize", member.length);
|
||||
|
@ -431,7 +431,7 @@
|
|||
roleIds: this.memberForm.roleIds,
|
||||
organizationId: this.currentRow.id
|
||||
};
|
||||
this.result = this.$post("user/orgmember/add", param,() => {
|
||||
this.result = this.$post("user/special/org/member/add", param,() => {
|
||||
this.cellClick(this.currentRow);
|
||||
this.addMemberVisible = false;
|
||||
})
|
||||
|
|
|
@ -270,7 +270,7 @@
|
|||
name: '',
|
||||
workspaceId: row.id
|
||||
};
|
||||
let path = "/user/member/list";
|
||||
let path = "/user/special/ws/member/list";
|
||||
this.result = this.$post(this.buildPagePath(path), param, res => {
|
||||
let data = res.data;
|
||||
this.memberLineData = data.listObject;
|
||||
|
@ -340,7 +340,7 @@
|
|||
name: '',
|
||||
workspaceId: this.items[i].id
|
||||
}
|
||||
let path = "user/member/list/all";
|
||||
let path = "user/special/ws/member/list/all";
|
||||
this.$post(path, param, res => {
|
||||
let member = res.data;
|
||||
this.$set(this.items[i], "memberSize", member.length);
|
||||
|
@ -376,7 +376,7 @@
|
|||
roleIds: this.memberForm.roleIds,
|
||||
workspaceId: this.currentWorkspaceRow.id
|
||||
};
|
||||
this.result = this.$post("user/member/add", param,() => {
|
||||
this.result = this.$post("user/special/ws/member/add", param,() => {
|
||||
this.cellClick(this.currentWorkspaceRow);
|
||||
this.addMemberVisible = false;
|
||||
})
|
||||
|
@ -401,7 +401,7 @@
|
|||
cancelButtonText: this.$t('commons.cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.result = this.$get('/user/member/delete/' + this.currentWorkspaceRow.id + '/' + row.id, () => {
|
||||
this.result = this.$get('/user/special/ws/member/delete/' + this.currentWorkspaceRow.id + '/' + row.id, () => {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: this.$t('commons.delete_success')
|
||||
|
|
|
@ -113,10 +113,10 @@
|
|||
export default {
|
||||
data() {
|
||||
return {
|
||||
queryPath: '/user/list',
|
||||
deletePath: '/user/delete/',
|
||||
createPath: '/user/add',
|
||||
updatePath: '/user/update',
|
||||
queryPath: '/user/special/list',
|
||||
deletePath: '/user/special/delete/',
|
||||
createPath: '/user/special/add',
|
||||
updatePath: '/user/special/update',
|
||||
result: {},
|
||||
createVisible: false,
|
||||
updateVisible: false,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<el-card>
|
||||
<div slot="header">
|
||||
<el-row type="flex" justify="space-between" align="middle" v-permission="['test_manager']">
|
||||
<span class="title">成员
|
||||
<span class="title">{{$t('commons.member')}}
|
||||
<ms-create-box :tips="btnTips" :exec="create"/>
|
||||
</span>
|
||||
<span class="search">
|
||||
|
@ -126,7 +126,7 @@
|
|||
btnTips: "添加工作空间成员",
|
||||
createVisible: false,
|
||||
updateVisible: false,
|
||||
queryPath: "/user/member/list",
|
||||
queryPath: "/user/ws/member/list",
|
||||
condition: "",
|
||||
tableData: [],
|
||||
rules: {
|
||||
|
@ -198,7 +198,7 @@
|
|||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.loading = true;
|
||||
this.$get('/user/member/delete/' + this.currentUser().lastWorkspaceId + '/' + row.id).then(() => {
|
||||
this.$get('/user/ws/member/delete/' + this.currentUser().lastWorkspaceId + '/' + row.id).then(() => {
|
||||
this.initTableData();
|
||||
this.loading = false;
|
||||
});
|
||||
|
@ -256,7 +256,7 @@
|
|||
});
|
||||
return false;
|
||||
}
|
||||
this.$post('/user/orgmember/list/all', param,response => {
|
||||
this.$post('/user/org/member/list/all', param,response => {
|
||||
this.createVisible = true;
|
||||
this.$set(this.form, "userList", response.data);
|
||||
})
|
||||
|
@ -272,7 +272,7 @@
|
|||
roleIds: this.form.roleIds,
|
||||
workspaceId: this.currentUser().lastWorkspaceId
|
||||
};
|
||||
this.result = this.$post("user/member/add", param, () => {
|
||||
this.result = this.$post("user/ws/member/add", param, () => {
|
||||
this.initTableData();
|
||||
this.createVisible = false;
|
||||
})
|
||||
|
|
|
@ -81,10 +81,13 @@
|
|||
window.location.reload();
|
||||
return;
|
||||
}
|
||||
|
||||
let testId = to.path.split('/')[4]; // find testId
|
||||
if (testId) {
|
||||
this.$get('/testplan/get/' + testId, response => {
|
||||
this.testPlan = response.data;
|
||||
if(response.data){
|
||||
this.testPlan = response.data;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<i class="el-icon-time"/>
|
||||
{{$t('load_test.recent')}}
|
||||
</div>
|
||||
<el-menu-item :key="t.id" v-for="t in recentTestPlans" :index="'/editTest/' + t.id">
|
||||
<el-menu-item :key="t.id" v-for="t in recentTestPlans" :index="'/functional/plan/edit/' + t.id">
|
||||
{{ t.name }}
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
|
@ -12,14 +12,13 @@
|
|||
|
||||
<script>
|
||||
import {ROLE_TEST_MANAGER, ROLE_TEST_USER, ROLE_TEST_VIEWER} from "../../../common/constants";
|
||||
import {hasRoles} from "../../../common/utils";
|
||||
|
||||
export default {
|
||||
name: "PerformanceRecentTestPlan",
|
||||
mounted() {
|
||||
const rolesString = localStorage.getItem("roles");
|
||||
const roles = rolesString.split(',');
|
||||
|
||||
if (roles.indexOf(ROLE_TEST_MANAGER) > -1 || roles.indexOf(ROLE_TEST_USER) > -1 || roles.indexOf(ROLE_TEST_VIEWER) > -1) {
|
||||
if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {
|
||||
this.$get('/testplan/recent/5', (response) => {
|
||||
this.recentTestPlans = response.data;
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<div>
|
||||
<transition>
|
||||
<keep-alive>
|
||||
<router-view/>
|
||||
<router-view :beaseUrl="beaseUrl"/>
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div>
|
||||
<h1>性能测试首页</h1>
|
||||
<h1>功能测试首页</h1>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<i class="el-icon-time"/>
|
||||
{{$t('load_test.recent')}}
|
||||
</div>
|
||||
<el-menu-item :key="t.id" v-for="t in recentTestPlans" :index="'/editTest/' + t.id">
|
||||
<el-menu-item :key="t.id" v-for="t in recentTestPlans" :index="'/performance/plan/edit/' + t.id">
|
||||
{{ t.name }}
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<div>
|
||||
<transition>
|
||||
<keep-alive>
|
||||
<router-view/>
|
||||
<router-view :beaseUrl="beaseUrl"/>
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</div>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
<script>
|
||||
export default {
|
||||
name: "PerformanceTestHome"
|
||||
name: "PerformanceTestHome"
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -217,7 +217,10 @@
|
|||
}
|
||||
},
|
||||
watch: {
|
||||
'$route'(to) {
|
||||
'$route'(to, from) {
|
||||
if(from.name != 'createPerTest' || from.name != 'editPerTest'){
|
||||
return;
|
||||
}
|
||||
let testId = to.path.split('/')[4];
|
||||
if (testId) {
|
||||
this.getAdvancedConfig(testId);
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
<el-input-number
|
||||
placeholder=""
|
||||
:min="1"
|
||||
:max="Math.min(threadNumber, duration)"
|
||||
:max="Math.min(threadNumber, rampUpTime)"
|
||||
v-model="step"
|
||||
@change="calculateChart"
|
||||
size="mini"/>
|
||||
|
@ -75,8 +75,7 @@
|
|||
</el-form>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
压力预估图
|
||||
<chart ref="chart1" :options="orgOptions" :auto-resize="true"></chart>
|
||||
<chart class="chart-container" ref="chart1" :options="orgOptions" :autoresize="true"></chart>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
@ -113,7 +112,10 @@
|
|||
}
|
||||
},
|
||||
watch: {
|
||||
'$route'(to) {
|
||||
'$route'(to, from) {
|
||||
if(from.name != 'createPerTest' || from.name != 'editPerTest'){
|
||||
return;
|
||||
}
|
||||
let testId = to.path.split('/')[4];
|
||||
if (testId) {
|
||||
this.getLoadConfig(testId);
|
||||
|
@ -124,52 +126,56 @@
|
|||
},
|
||||
methods: {
|
||||
getLoadConfig(testId) {
|
||||
this.$get('/testplan/get-load-config/' + testId, (response) => {
|
||||
if (response.data) {
|
||||
let data = JSON.parse(response.data);
|
||||
if(testId) {
|
||||
|
||||
data.forEach(d => {
|
||||
switch (d.key) {
|
||||
case TARGET_LEVEL:
|
||||
this.threadNumber = d.value;
|
||||
break;
|
||||
case RAMP_UP:
|
||||
this.rampUpTime = d.value;
|
||||
break;
|
||||
case DURATION:
|
||||
this.duration = d.value;
|
||||
break;
|
||||
case STEPS:
|
||||
this.step = d.value;
|
||||
break;
|
||||
case RPS_LIMIT:
|
||||
this.rpsLimit = d.value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
this.$get('/testplan/get-load-config/' + testId, (response) => {
|
||||
if (response.data && response.data != "") {
|
||||
let data = JSON.parse(response.data);
|
||||
|
||||
this.threadNumber = this.threadNumber || 10;
|
||||
this.duration = this.duration || 30;
|
||||
this.rampUpTime = this.rampUpTime || 12;
|
||||
this.step = this.step || 3;
|
||||
this.rpsLimit = this.rpsLimit || 10;
|
||||
data.forEach(d => {
|
||||
switch (d.key) {
|
||||
case TARGET_LEVEL:
|
||||
this.threadNumber = d.value;
|
||||
break;
|
||||
case RAMP_UP:
|
||||
this.rampUpTime = d.value;
|
||||
break;
|
||||
case DURATION:
|
||||
this.duration = d.value;
|
||||
break;
|
||||
case STEPS:
|
||||
this.step = d.value;
|
||||
break;
|
||||
case RPS_LIMIT:
|
||||
this.rpsLimit = d.value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
this.calculateChart();
|
||||
}
|
||||
});
|
||||
this.threadNumber = this.threadNumber || 10;
|
||||
this.duration = this.duration || 30;
|
||||
this.rampUpTime = this.rampUpTime || 12;
|
||||
this.step = this.step || 3;
|
||||
this.rpsLimit = this.rpsLimit || 10;
|
||||
|
||||
this.calculateChart();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
calculateChart() {
|
||||
if (this.duration < this.rampUpTime) {
|
||||
this.rampUpTime = this.duration;
|
||||
}
|
||||
if (this.threadNumber < this.step) {
|
||||
this.step = this.threadNumber;
|
||||
if (this.rampUpTime < this.step) {
|
||||
this.step = this.rampUpTime;
|
||||
}
|
||||
this.orgOptions = {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: []
|
||||
},
|
||||
yAxis: {
|
||||
|
@ -177,6 +183,7 @@
|
|||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: '{a}: {c0}',
|
||||
axisPointer: {
|
||||
lineStyle: {
|
||||
color: '#57617B'
|
||||
|
@ -184,11 +191,11 @@
|
|||
}
|
||||
},
|
||||
series: [{
|
||||
name: 'User',
|
||||
data: [],
|
||||
type: 'line',
|
||||
step: 'start',
|
||||
smooth: false,
|
||||
symbol: 'circle',
|
||||
symbolSize: 5,
|
||||
showSymbol: false,
|
||||
lineStyle: {
|
||||
|
@ -219,16 +226,23 @@
|
|||
}]
|
||||
};
|
||||
let timePeriod = Math.floor(this.rampUpTime / this.step);
|
||||
let threadPeriod = Math.floor(this.threadNumber / this.step);
|
||||
let threadInc = threadPeriod;
|
||||
let timeInc = timePeriod;
|
||||
|
||||
for (let i = 0; i < this.duration; i++) {
|
||||
let threadPeriod = Math.floor(this.threadNumber / this.step);
|
||||
let threadInc1 = Math.floor(this.threadNumber / this.step);
|
||||
let threadInc2 = Math.ceil(this.threadNumber / this.step);
|
||||
let inc2count = this.threadNumber - this.step * threadInc1;
|
||||
for (let i = 0; i <= this.duration; i++) {
|
||||
// x 轴
|
||||
this.orgOptions.xAxis.data.push(i);
|
||||
if (i > timePeriod) {
|
||||
threadPeriod = threadPeriod + threadInc;
|
||||
timePeriod += timeInc;
|
||||
if (inc2count > 0) {
|
||||
threadPeriod = threadPeriod + threadInc2;
|
||||
inc2count--;
|
||||
} else {
|
||||
threadPeriod = threadPeriod + threadInc1;
|
||||
}
|
||||
if (threadPeriod > this.threadNumber) {
|
||||
threadPeriod = this.threadNumber;
|
||||
}
|
||||
|
@ -237,9 +251,6 @@
|
|||
this.orgOptions.series[0].data.push(threadPeriod);
|
||||
}
|
||||
}
|
||||
//
|
||||
this.orgOptions.xAxis.data.push(this.duration);
|
||||
this.orgOptions.series[0].data.push(this.threadNumber);
|
||||
},
|
||||
convertProperty() {
|
||||
/// todo:下面4个属性是jmeter ConcurrencyThreadGroup plugin的属性,这种硬编码不太好吧,在哪能转换这种属性?
|
||||
|
|
Loading…
Reference in New Issue