Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
haifeng414 2020-02-20 20:01:15 +08:00
commit 36544f3621
12 changed files with 250 additions and 118 deletions

View File

@ -15,6 +15,9 @@
<if test="request.name != null"> <if test="request.name != null">
and load_test.name like CONCAT('%', #{request.name},'%') and load_test.name like CONCAT('%', #{request.name},'%')
</if> </if>
<if test="request.workspaceId != null">
AND project.workspace_id = #{request.workspaceId}
</if>
</where> </where>
</select> </select>

View File

@ -9,6 +9,7 @@ import io.metersphere.controller.request.testplan.*;
import io.metersphere.dto.LoadTestDTO; import io.metersphere.dto.LoadTestDTO;
import io.metersphere.service.FileService; import io.metersphere.service.FileService;
import io.metersphere.service.LoadTestService; import io.metersphere.service.LoadTestService;
import io.metersphere.user.SessionUtils;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@ -29,6 +30,7 @@ public class LoadTestController {
@PostMapping("/list/{goPage}/{pageSize}") @PostMapping("/list/{goPage}/{pageSize}")
public Pager<List<LoadTestDTO>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestPlanRequest request) { public Pager<List<LoadTestDTO>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestPlanRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true); Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
return PageUtils.setPageInfo(page, loadTestService.list(request)); return PageUtils.setPageInfo(page, loadTestService.list(request));
} }
@ -64,12 +66,11 @@ public class LoadTestController {
} }
@PostMapping("/file/download") @PostMapping("/file/download")
public ResponseEntity<org.springframework.core.io.Resource> downloadJmx(@RequestBody FileOperationRequest fileOperationRequest) { public ResponseEntity<byte[]> downloadJmx(@RequestBody FileOperationRequest fileOperationRequest) {
org.springframework.core.io.Resource resource = fileService.loadFileAsResource(fileOperationRequest.getName()); byte[] bytes = fileService.loadFileAsBytes(fileOperationRequest.getId());
return ResponseEntity.ok() return ResponseEntity.ok()
.contentType(MediaType.parseMediaType("application/octet-stream")) .contentType(MediaType.parseMediaType("application/octet-stream"))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileOperationRequest.getName() + "\"") .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileOperationRequest.getName() + "\"")
.body(resource); .body(bytes);
} }
} }

View File

@ -23,8 +23,10 @@ public class ProjectController {
@GetMapping("/listAll") @GetMapping("/listAll")
public List<Project> listAll() { public List<Project> listAll() {
// todo: 限制workspace和org String currentWorkspaceId = SessionUtils.getCurrentWorkspaceId();
return projectService.listAll(); ProjectRequest request = new ProjectRequest();
request.setWorkspaceId(currentWorkspaceId);
return projectService.getProjectList(request);
} }
@PostMapping("/add") @PostMapping("/add")

View File

@ -1,8 +1,17 @@
package io.metersphere.controller.request.testplan; package io.metersphere.controller.request.testplan;
public class FileOperationRequest { public class FileOperationRequest {
private String id;
private String name; private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() { public String getName() {
return name; return name;
} }

View File

@ -2,6 +2,7 @@ package io.metersphere.controller.request.testplan;
public class QueryTestPlanRequest extends TestPlanRequest { public class QueryTestPlanRequest extends TestPlanRequest {
private String name; private String name;
private String workspaceId;
@Override @Override
public String getName() { public String getName() {
@ -12,4 +13,12 @@ public class QueryTestPlanRequest extends TestPlanRequest {
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
public String getWorkspaceId() {
return workspaceId;
}
public void setWorkspaceId(String workspaceId) {
this.workspaceId = workspaceId;
}
} }

View File

@ -38,18 +38,10 @@ public class FileService {
fileMap.put(name, file); fileMap.put(name, file);
} }
public org.springframework.core.io.Resource loadFileAsResource(String name) { public byte[] loadFileAsBytes(String id) {
final MultipartFile file = fileMap.get(name); FileContent fileContent = fileContentMapper.selectByPrimaryKey(id);
if (file != null) { return fileContent.getFile();
try {
return new InputStreamResource(file.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
} }
public FileMetadata getFileMetadataByTestId(String testId) { public FileMetadata getFileMetadataByTestId(String testId) {

View File

@ -1,8 +1,15 @@
<template> <template>
<el-col v-if="auth"> <el-col v-if="auth">
<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="4">
<a class="logo"/> <a class="logo"/>
</el-col>
<el-col :span="10">
<ms-top-menus/>
</el-col>
<el-col :span="10">
<ms-user/> <ms-user/>
</el-col>
</el-row> </el-row>
<el-row id="header-bottom" type="flex" justify="space-between" align="middle"> <el-row id="header-bottom" type="flex" justify="space-between" align="middle">
<el-col :span="10"> <el-col :span="10">
@ -26,6 +33,7 @@
<script> <script>
import MsMenus from "./components/HeaderMenus"; import MsMenus from "./components/HeaderMenus";
import MsTopMenus from "./components/HeaderTopMenus";
import MsSetting from "./components/HeaderSetting"; import MsSetting from "./components/HeaderSetting";
import MsView from "./components/router/View"; import MsView from "./components/router/View";
import MsUser from "./components/HeaderUser"; import MsUser from "./components/HeaderUser";
@ -49,7 +57,7 @@
window.location.href = "/login" window.location.href = "/login"
}); });
}, },
components: {MsWebSocket, MsUser, MsMenus, MsSetting, MsView}, components: {MsWebSocket, MsUser, MsMenus, MsSetting, MsView, MsTopMenus},
methods: { methods: {
} }
} }

View File

@ -2,36 +2,14 @@
<el-menu class="header-menu" :unique-opened="true" mode="horizontal" router <el-menu class="header-menu" :unique-opened="true" mode="horizontal" router
menu-trigger="click"> menu-trigger="click">
<el-menu-item index="1"><a href="/" style="text-decoration: none;">{{ $t("i18n.home") }}</a></el-menu-item> <el-menu-item index="1"><a href="/" style="text-decoration: none;">{{ $t("i18n.home") }}</a></el-menu-item>
<el-submenu index="7" popper-class="submenu">
<template slot="title">组织</template>
<label v-for="(item,index) in organizationList" :key="index">
<el-menu-item @click="clickMenu(item)">{{item.name}}
<i class="el-icon-check"
v-if="item.id === currentUserInfo.lastSourceId || item.id === workspaceParentId"></i>
</el-menu-item>
</label>
</el-submenu>
<el-submenu index="2" popper-class="submenu">
<template slot="title">工作空间</template>
<label v-for="(item,index) in workspaceList" :key="index">
<el-menu-item @click="clickMenu(item)">
{{item.name}}
<i class="el-icon-check" v-if="item.id === currentUserInfo.lastSourceId"></i>
</el-menu-item>
</label>
</el-submenu>
<el-submenu index="3" popper-class="submenu" v-permission="['test_manager']"> <el-submenu index="3" popper-class="submenu" v-permission="['test_manager']">
<template slot="title">项目</template> <template slot="title">项目</template>
<el-menu-item index="3-1">项目1</el-menu-item> <recent-project/>
<el-menu-item index="3-2">项目2</el-menu-item>
<el-divider/> <el-divider/>
<el-menu-item index="/project"> <el-menu-item index="/project">
<font-awesome-icon :icon="['fa', 'list-ul']"/> <font-awesome-icon :icon="['fa', 'list-ul']"/>
<span style="padding-left: 5px;">显示全部</span> <span style="padding-left: 5px;">显示全部</span>
</el-menu-item> </el-menu-item>
<el-menu-item index="/createProject">
<el-button type="text">创建项目</el-button>
</el-menu-item>
</el-submenu> </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']">
<template slot="title">测试</template> <template slot="title">测试</template>
@ -56,68 +34,11 @@
<script> <script>
import RecentTestPlan from "./testPlan/RecentTestPlan"; import RecentTestPlan from "./testPlan/RecentTestPlan";
import Cookies from "js-cookie"; import RecentProject from "./project/RecentProject";
import {TokenKey} from "../../common/constants";
export default { export default {
name: "MsMenus", name: "MsMenus",
components: {RecentTestPlan}, components: {RecentTestPlan, RecentProject}
created() {
this.initMenuData();
this.getCurrentUserInfo();
},
computed: {
workspaceParentId() {
let result = '';
if (this.workspaceIds.includes(this.currentUserInfo.lastSourceId)) {
let obj = this.workspaceList.filter(r => r.id === this.currentUserInfo.lastSourceId);
if (obj.length > 0) {
result = obj[0].organizationId;
}
}
return result;
}
},
data() {
return {
organizationList: [
{index: '7-1', name: '组织1'},
],
workspaceList: [
{index: '2-1', name: '无工作空间'},
],
currentUserInfo: {},
currentUserId: JSON.parse(Cookies.get(TokenKey)).id,
workspaceIds: []
}
},
methods: {
initMenuData() {
this.$get("/organization/list/userorg/" + this.currentUserId, response => {
this.organizationList = response.data;
})
this.$get("/workspace/list/userworkspace/" + this.currentUserId, response => {
this.workspaceList = response.data;
this.workspaceIds = response.data.map(r => r.id);
})
},
getCurrentUserInfo() {
this.$get("/user/info/" + this.currentUserId, response => {
this.currentUserInfo = response.data;
})
},
clickMenu(data) {
if (data.id === this.currentUserInfo.lastSourceId) {
return false;
}
window.console.log(data.id);
let user = {};
user.id = this.currentUserInfo.id;
user.lastSourceId = data.id;
this.$post("/user/switch/source/" + user.lastSourceId, {});
window.location.reload();
}
}
} }
</script> </script>
@ -143,8 +64,4 @@
.el-divider--horizontal { .el-divider--horizontal {
margin: 0; margin: 0;
} }
.el-icon-check {
color: #44b349;
}
</style> </style>

View File

@ -0,0 +1,39 @@
<template>
<el-menu mode="horizontal" menu-trigger="click"
background-color="rgb(44, 42, 72)"
class="header-top-menus"
text-color="#F2F2F2"
active-text-color="#fff"
:default-active="$route.path"
router>
<el-menu-item index="1">功能测试</el-menu-item>
<el-menu-item index="/createTest" onselectstart="return false">性能测试</el-menu-item>
<el-menu-item index="/setting" onselectstart="return false">系统设置</el-menu-item>
</el-menu>
</template>
<script>
export default {
name: "MsTopMenus"
}
</script>
<style>
.header-top-menus.el-menu--horizontal > li {
height: 40px;
line-height: 40px;
color: inherit;
}
.header-top-menus.el-menu--horizontal > li.el-submenu > * {
height: 39px;
line-height: 40px;
color: inherit;
}
.header-top-menus.el-menu--horizontal > li.is-active {
background: #595591 !important;
}
</style>
<style scoped>
</style>

View File

@ -1,4 +1,33 @@
<template> <template>
<el-row>
<el-col :span="10" :offset="8">
<el-menu :unique-opened="true" mode="horizontal" router
menu-trigger="click"
class="header-user-menu"
background-color="rgb(44, 42, 72)"
text-color="#fff">
<el-submenu index="1" popper-class="submenu">
<template slot="title">组织</template>
<label v-for="(item,index) in organizationList" :key="index">
<el-menu-item @click="clickMenu(item)">{{item.name}}
<i class="el-icon-check"
v-if="item.id === currentUserInfo.lastSourceId || item.id === workspaceParentId"></i>
</el-menu-item>
</label>
</el-submenu>
<el-submenu index="2" popper-class="submenu">
<template slot="title">工作空间</template>
<label v-for="(item,index) in workspaceList" :key="index">
<el-menu-item @click="clickMenu(item)">
{{item.name}}
<i class="el-icon-check" v-if="item.id === currentUserInfo.lastSourceId"></i>
</el-menu-item>
</label>
</el-submenu>
</el-menu>
</el-col>
<el-col :span="3" :offset="3">
<el-dropdown size="medium" @command="handleCommand"> <el-dropdown size="medium" @command="handleCommand">
<span class="dropdown-link"> <span class="dropdown-link">
{{currentUser.name}}<i class="el-icon-caret-bottom el-icon--right"/> {{currentUser.name}}<i class="el-icon-caret-bottom el-icon--right"/>
@ -8,6 +37,8 @@
<el-dropdown-item command="logout">退出系统</el-dropdown-item> <el-dropdown-item command="logout">退出系统</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
</el-col>
</el-row>
</template> </template>
<script> <script>
@ -16,11 +47,38 @@
export default { export default {
name: "MsUser", name: "MsUser",
created() {
this.initMenuData();
this.getCurrentUserInfo();
},
data() {
return {
organizationList: [
{index: '7-1', name: '组织1'},
],
workspaceList: [
{index: '2-1', name: '无工作空间'},
],
currentUserInfo: {},
currentUserId: JSON.parse(Cookies.get(TokenKey)).id,
workspaceIds: []
}
},
computed: { computed: {
currentUser: () => { currentUser: () => {
let user = Cookies.get(TokenKey); let user = Cookies.get(TokenKey);
window.console.log(user); window.console.log(user);
return JSON.parse(user); return JSON.parse(user);
},
workspaceParentId() {
let result = '';
if (this.workspaceIds.includes(this.currentUserInfo.lastSourceId)) {
let obj = this.workspaceList.filter(r => r.id === this.currentUserInfo.lastSourceId);
if (obj.length > 0) {
result = obj[0].organizationId;
}
}
return result;
} }
}, },
methods: { methods: {
@ -38,15 +96,54 @@
default: default:
break; break;
} }
},
initMenuData() {
this.$get("/organization/list/userorg/" + this.currentUserId, response => {
this.organizationList = response.data;
})
this.$get("/workspace/list/userworkspace/" + this.currentUserId, response => {
this.workspaceList = response.data;
this.workspaceIds = response.data.map(r => r.id);
})
},
getCurrentUserInfo() {
this.$get("/user/info/" + this.currentUserId, response => {
this.currentUserInfo = response.data;
})
},
clickMenu(data) {
if (data.id === this.currentUserInfo.lastSourceId) {
return false;
}
window.console.log(data.id);
let user = {};
user.id = this.currentUserInfo.id;
user.lastSourceId = data.id;
this.$post("/user/switch/source/" + user.lastSourceId, {});
window.location.reload();
} }
} }
} }
</script> </script>
<style>
.header-user-menu.el-menu--horizontal > li.el-submenu > * {
height: 40px;
line-height: 40px;
color: inherit;
}
</style>
<style scoped> <style scoped>
.dropdown-link { .dropdown-link {
cursor: pointer; cursor: pointer;
font-size: 12px; font-size: 12px;
color: rgb(245, 245, 245); color: rgb(245, 245, 245);
line-height: 40px;
}
.el-icon-check {
color: #44b349;
margin-left: 10px;
} }
</style> </style>

View File

@ -0,0 +1,46 @@
<template>
<div>
<div class="recent-text">
<i class="el-icon-time"/>
最近的项目
</div>
<el-menu-item v-bind:key="recentTestPlan.id" v-for="recentTestPlan in recentTestPlans">
{{ recentTestPlan.name }}
</el-menu-item>
</div>
</template>
<script>
export default {
name: "RecentProject",
data() {
return {
recentTestPlans: [
{
id: 1,
name: "项目1"
},
{
id: 2,
name: "项目2"
},
{
id: 3,
name: "项目3"
},
{
id: 4,
name: "项目4"
}
]
}
}
}
</script>
<style scoped>
.recent-text {
padding-left: 10%;
color: #777777;
}
</style>

View File

@ -53,7 +53,7 @@
</template> </template>
<script> <script>
import Message from "element-ui"; import {Message} from "element-ui";
export default { export default {
name: "TestPlanBasicConfig", name: "TestPlanBasicConfig",
@ -91,6 +91,7 @@
}); });
this.tableData.push({ this.tableData.push({
id: file.id,
name: file.name, name: file.name,
size: file.size + 'Byte', /// todo: ByteKBMB size: file.size + 'Byte', /// todo: ByteKBMB
type: 'JMX', type: 'JMX',
@ -120,10 +121,16 @@
}, },
handleDownload(file) { handleDownload(file) {
let data = { let data = {
name: file.name name: file.name,
id: file.id,
}; };
let config = {
this.result = this.$post(this.jmxDownloadPath, data, response => { url: this.jmxDownloadPath,
method: 'post',
data: data,
responseType: 'blob'
};
this.result = this.$request(config).then(response => {
const content = response.data; const content = response.data;
const blob = new Blob([content]); const blob = new Blob([content]);
if ("download" in document.createElement("a")) { if ("download" in document.createElement("a")) {
@ -131,13 +138,15 @@
// chrome/firefox // chrome/firefox
let aTag = document.createElement('a'); let aTag = document.createElement('a');
aTag.download = file.name; aTag.download = file.name;
aTag.href = URL.createObjectURL(blob) aTag.href = URL.createObjectURL(blob);
aTag.click(); aTag.click();
URL.revokeObjectURL(aTag.href) URL.revokeObjectURL(aTag.href)
} else { } else {
// IE10+ // IE10+
navigator.msSaveBlob(blob, this.filename) navigator.msSaveBlob(blob, this.filename)
} }
}).catch(e => {
Message.error({message: e.message, showClose: true});
}); });
}, },
handleDelete(file, index) { handleDelete(file, index) {