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

This commit is contained in:
W23123 2020-02-18 17:20:44 +08:00
commit 7773eda15a
12 changed files with 204 additions and 77 deletions

View File

@ -53,6 +53,11 @@ public class LoadTestController {
loadTestService.delete(request); loadTestService.delete(request);
} }
@PostMapping("/run")
public void delete(@RequestBody RunTestPlanRequest request) {
loadTestService.run(request);
}
@GetMapping("/file/metadata/{testId}") @GetMapping("/file/metadata/{testId}")
public FileMetadata getFileMetadata(@PathVariable String testId) { public FileMetadata getFileMetadata(@PathVariable String testId) {
return fileService.getFileMetadataByTestId(testId); return fileService.getFileMetadataByTestId(testId);

View File

@ -3,9 +3,11 @@ package io.metersphere.controller;
import com.github.pagehelper.Page; import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.Project; import io.metersphere.base.domain.Project;
import io.metersphere.commons.constants.RoleConstants;
import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.Pager;
import io.metersphere.service.ProjectService; import io.metersphere.service.ProjectService;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -24,22 +26,26 @@ public class ProjectController {
} }
@PostMapping("/add") @PostMapping("/add")
@RequiresRoles(RoleConstants.TEST_MANAGER)
public Project addProject(@RequestBody Project project) { public Project addProject(@RequestBody Project project) {
return projectService.addProject(project); return projectService.addProject(project);
} }
@PostMapping("/list/{goPage}/{pageSize}") @PostMapping("/list/{goPage}/{pageSize}")
@RequiresRoles(RoleConstants.TEST_MANAGER)
public Pager<List<Project>> getProjectList(@PathVariable int goPage, @PathVariable int pageSize) { public Pager<List<Project>> getProjectList(@PathVariable int goPage, @PathVariable int pageSize) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true); Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, projectService.getProjectList()); return PageUtils.setPageInfo(page, projectService.getProjectList());
} }
@GetMapping("/delete/{projectId}") @GetMapping("/delete/{projectId}")
@RequiresRoles(RoleConstants.TEST_MANAGER)
public void deleteProject(@PathVariable(value = "projectId") String projectId) { public void deleteProject(@PathVariable(value = "projectId") String projectId) {
projectService.deleteProject(projectId); projectService.deleteProject(projectId);
} }
@PostMapping("/update") @PostMapping("/update")
@RequiresRoles(RoleConstants.TEST_MANAGER)
public void updateProject(@RequestBody Project Project) { public void updateProject(@RequestBody Project Project) {
projectService.updateProject(Project); projectService.updateProject(Project);
} }

View File

@ -1,7 +1,13 @@
package io.metersphere.controller; package io.metersphere.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.Workspace; import io.metersphere.base.domain.Workspace;
import io.metersphere.commons.constants.RoleConstants;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.service.WorkspaceService; import io.metersphere.service.WorkspaceService;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -13,18 +19,30 @@ public class WorkspaceController {
@Resource @Resource
private WorkspaceService workspaceService; private WorkspaceService workspaceService;
@PostMapping("save") @PostMapping("add")
public Workspace saveWorkspace(@RequestBody Workspace workspace) { @RequiresRoles(RoleConstants.ORG_ADMIN)
public Workspace addWorkspace(@RequestBody Workspace workspace) {
return workspaceService.saveWorkspace(workspace);
}
@PostMapping("update")
@RequiresRoles(RoleConstants.ORG_ADMIN)
public Workspace updateWorkspace(@RequestBody Workspace workspace) {
workspaceService.checkOwner(workspace.getId());
return workspaceService.saveWorkspace(workspace); return workspaceService.saveWorkspace(workspace);
} }
@GetMapping("delete/{workspaceId}") @GetMapping("delete/{workspaceId}")
@RequiresRoles(RoleConstants.ORG_ADMIN)
public void saveWorkspace(@PathVariable String workspaceId) { public void saveWorkspace(@PathVariable String workspaceId) {
workspaceService.checkOwner(workspaceId);
workspaceService.deleteWorkspace(workspaceId); workspaceService.deleteWorkspace(workspaceId);
} }
@PostMapping("list") @PostMapping("list/{goPage}/{pageSize}")
public List<Workspace> getWorkspaceList() { @RequiresRoles(RoleConstants.ORG_ADMIN)
return workspaceService.getWorkspaceList(); public Pager<List<Workspace>> getWorkspaceList(@PathVariable int goPage, @PathVariable int pageSize) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, workspaceService.getWorkspaceList());
} }
} }

View File

@ -0,0 +1,4 @@
package io.metersphere.controller.request.testplan;
public class RunTestPlanRequest extends TestPlanRequest {
}

View File

@ -6,10 +6,7 @@ import io.metersphere.base.mapper.ext.ExtLoadTestMapper;
import io.metersphere.commons.constants.LoadTestFileType; import io.metersphere.commons.constants.LoadTestFileType;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.IOUtils; import io.metersphere.commons.utils.IOUtils;
import io.metersphere.controller.request.testplan.DeleteTestPlanRequest; import io.metersphere.controller.request.testplan.*;
import io.metersphere.controller.request.testplan.EditTestPlanRequest;
import io.metersphere.controller.request.testplan.QueryTestPlanRequest;
import io.metersphere.controller.request.testplan.SaveTestPlanRequest;
import io.metersphere.dto.LoadTestDTO; import io.metersphere.dto.LoadTestDTO;
import org.apache.commons.lang3.RandomUtils; import org.apache.commons.lang3.RandomUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -147,4 +144,13 @@ public class LoadTestService {
loadTestMapper.updateByPrimaryKeySelective(loadTest); loadTestMapper.updateByPrimaryKeySelective(loadTest);
} }
} }
public void run(RunTestPlanRequest request) {
final LoadTestWithBLOBs loadTest = loadTestMapper.selectByPrimaryKey(request.getId());
if (loadTest == null) {
MSException.throwException("无法运行测试,未找到测试:" + request.getId());
}
System.out.println("开始运行:" + loadTest.getName());
}
} }

View File

@ -45,4 +45,9 @@ public class WorkspaceService {
public void deleteWorkspace(String workspaceId) { public void deleteWorkspace(String workspaceId) {
workspaceMapper.deleteByPrimaryKey(workspaceId); workspaceMapper.deleteByPrimaryKey(workspaceId);
} }
public void checkOwner(String workspaceId) {
// TODO 验证当前用户是否拥有当前此空间权限
}
} }

View File

@ -10,8 +10,36 @@ const options = function (value, array) {
return value; return value;
}; };
const timestampFormatDate = function (timestamp) {
if (!timestamp) {
return timestamp
}
let date = new Date(timestamp);
let y = date.getFullYear();
let MM = date.getMonth() + 1;
MM = MM < 10 ? ('0' + MM) : MM;
let d = date.getDate();
d = d < 10 ? ('0' + d) : d;
let h = date.getHours();
h = h < 10 ? ('0' + h) : h;
let m = date.getMinutes();
m = m < 10 ? ('0' + m) : m;
let s = date.getSeconds();
s = s < 10 ? ('0' + s) : s;
return y + '-' + MM + '-' + d + ' ' + h + ':' + m + ':' + s
};
const filters = { const filters = {
"options": options, "options": options,
"timestampFormatDate": timestampFormatDate,
}; };
export default { export default {

View File

@ -1,27 +0,0 @@
let timestampFormatDate = function (timestamp) {
if (!timestamp) {
return timestamp
}
let date = new Date(timestamp);
let y = date.getFullYear();
let MM = date.getMonth() + 1;
MM = MM < 10 ? ('0' + MM) : MM;
let d = date.getDate();
d = d < 10 ? ('0' + d) : d;
let h = date.getHours();
h = h < 10 ? ('0' + h) : h;
let m = date.getMinutes();
m = m < 10 ? ('0' + m) : m;
let s = date.getSeconds();
s = s < 10 ? ('0' + s) : s;
return y + '-' + MM + '-' + d + ' ' + h + ':' + m + ':' + s
};
export default timestampFormatDate

View File

@ -4,7 +4,10 @@
<el-card> <el-card>
<div slot="header"> <div slot="header">
<el-row type="flex" justify="space-between" align="middle"> <el-row type="flex" justify="space-between" align="middle">
<span class="title">项目</span> <span class="title">
项目
<ms-create-box :tips="btnTips" :exec="create"/>
</span>
<span class="search"> <span class="search">
<el-input type="text" size="small" placeholder="根据名称搜索" prefix-icon="el-icon-search" <el-input type="text" size="small" placeholder="根据名称搜索" prefix-icon="el-icon-search"
maxlength="60" v-model="condition" clearable/> maxlength="60" v-model="condition" clearable/>
@ -21,8 +24,24 @@
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<div>
<el-row>
<el-col :span="22" :offset="1">
<div class="table-page">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page.sync="currentPage"
:page-sizes="[5, 10, 20, 50, 100]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
</el-col>
</el-row>
</div>
</el-card> </el-card>
<ms-create-box :tips="btnTips" :exec="create"/>
<el-dialog title="创建项目" :visible.sync="createVisible"> <el-dialog title="创建项目" :visible.sync="createVisible">
<el-form :model="form" :rules="rules" ref="form" label-position="left" label-width="100px" size="small"> <el-form :model="form" :rules="rules" ref="form" label-position="left" label-width="100px" size="small">
@ -56,6 +75,9 @@
condition: "", condition: "",
items: [], items: [],
form: {}, form: {},
currentPage: 1,
pageSize: 5,
total: 0,
rules: { rules: {
name: [ name: [
{required: true, message: '请输入项目名称', trigger: 'blur'}, {required: true, message: '请输入项目名称', trigger: 'blur'},
@ -113,10 +135,19 @@
}); });
}, },
list() { list() {
this.$post("/project/list/1/10", {}, (response) => { let url = "/project/list/" + this.currentPage + '/' + this.pageSize;
this.$post(url, {}, (response) => {
this.items = response.data; this.items = response.data;
}) })
} },
handleSizeChange(size) {
this.pageSize = size;
this.list();
},
handleCurrentChange(current) {
this.currentPage = current;
this.list();
},
} }
} }
</script> </script>

View File

@ -3,7 +3,10 @@
<el-card> <el-card>
<div slot="header"> <div slot="header">
<el-row type="flex" justify="space-between" align="middle"> <el-row type="flex" justify="space-between" align="middle">
<span class="title">工作空间</span> <span class="title">
工作空间
<ms-create-box :tips="btnTips" :exec="create"/>
</span>
<span class="search"> <span class="search">
<el-input type="text" size="small" placeholder="根据名称搜索" prefix-icon="el-icon-search" <el-input type="text" size="small" placeholder="根据名称搜索" prefix-icon="el-icon-search"
maxlength="60" v-model="condition" clearable/> maxlength="60" v-model="condition" clearable/>
@ -20,8 +23,25 @@
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<div>
<el-row>
<el-col :span="22" :offset="1">
<div class="table-page">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page.sync="currentPage"
:page-sizes="[5, 10, 20, 50, 100]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
</el-col>
</el-row>
</div>
</el-card> </el-card>
<ms-create-box :tips="btnTips" :exec="create"/>
<el-dialog title="创建工作空间" :visible.sync="createVisible" width="30%"> <el-dialog title="创建工作空间" :visible.sync="createVisible" width="30%">
<el-form :model="form" :rules="rules" ref="form" label-position="left" label-width="100px" size="small"> <el-form :model="form" :rules="rules" ref="form" label-position="left" label-width="100px" size="small">
<el-form-item label="名称" prop="name"> <el-form-item label="名称" prop="name">
@ -57,12 +77,16 @@
this.$refs[formName].validate((valid) => { this.$refs[formName].validate((valid) => {
if (valid) { if (valid) {
this.loading = true; this.loading = true;
this.$post("/workspace/save", this.form, () => { let saveType = 'add';
if (this.form.id) {
saveType = 'update'
}
this.$post("/workspace/" + saveType, this.form, () => {
this.createVisible = false; this.createVisible = false;
this.loading = false; this.loading = false;
this.list(); this.list();
Message.success('保存成功'); Message.success('保存成功');
}) });
} else { } else {
return false; return false;
} }
@ -96,10 +120,22 @@
}); });
}, },
list() { list() {
this.$post('/workspace/list', {}, response => { let url = '/workspace/list/' + this.currentPage + '/' + this.pageSize;
this.items = response.data; this.$post(url, {}, response => {
let data = response.data;
this.items = data.listObject;
this.total = data.itemCount;
}) })
} },
handleSizeChange(size) {
this.pageSize = size;
this.list();
},
handleCurrentChange(current) {
this.currentPage = current;
this.list();
},
}, },
data() { data() {
return { return {
@ -108,6 +144,9 @@
btnTips: "添加工作空间", btnTips: "添加工作空间",
condition: "", condition: "",
items: [], items: [],
currentPage: 1,
pageSize: 5,
total: 0,
form: { form: {
// name: "", // name: "",
// description: "" // description: ""

View File

@ -51,6 +51,7 @@
listProjectPath: "/project/listAll", listProjectPath: "/project/listAll",
savePath: "/testplan/save", savePath: "/testplan/save",
editPath: "/testplan/edit", editPath: "/testplan/edit",
runPath: "/testplan/run",
projects: [], projects: [],
active: '0', active: '0',
tabs: [{ tabs: [{
@ -85,28 +86,7 @@
return; return;
} }
let formData = new FormData(); let options = this.getSaveOption();
let url = this.testPlan.id ? this.editPath : this.savePath;
if (!this.testPlan.file.id) {
formData.append("file", this.testPlan.file);
}
// filejson
let requestJson = JSON.stringify(this.testPlan, function (key, value) {
return key === "file" ? undefined : value
});
formData.append('request', new Blob([requestJson], {
type: "application/json"
}));
let options = {
method: 'POST',
url: url,
data: formData,
headers: {
'Content-Type': undefined
}
};
this.$request(options).then(response => { this.$request(options).then(response => {
if (response) { if (response) {
@ -122,12 +102,48 @@
return; return;
} }
/// todo: saveAndRun let options = this.getSaveOption();
this.$message({
message: '保存成功,开始运行!', this.$request(options).then(response => {
type: 'success' if (response) {
this.$message({
message: '保存成功!',
type: 'success'
});
this.$post(this.runPath, {id: this.testPlan.id}).then(() => {
this.$message({
message: '正在运行!',
type: 'success'
});
})
}
}); });
}, },
getSaveOption() {
let formData = new FormData();
let url = this.testPlan.id ? this.editPath : this.savePath;
if (!this.testPlan.file.id) {
formData.append("file", this.testPlan.file);
}
// filejson
let requestJson = JSON.stringify(this.testPlan, function (key, value) {
return key === "file" ? undefined : value
});
formData.append('request', new Blob([requestJson], {
type: "application/json"
}));
return {
method: 'POST',
url: url,
data: formData,
headers: {
'Content-Type': undefined
}
};
},
cancel() { cancel() {
this.$router.push({path: '/'}) this.$router.push({path: '/'})
}, },

View File

@ -8,7 +8,6 @@ import App from './App.vue';
import router from "./components/router/router"; import router from "./components/router/router";
import './permission' // permission control import './permission' // permission control
import i18n from "../i18n/i18n"; import i18n from "../i18n/i18n";
import timestampFormatDate from "./components/common/filter/TimestampFormatDateFilter";
import store from "./store"; import store from "./store";
import {permission} from './permission' import {permission} from './permission'
@ -20,9 +19,6 @@ Vue.use(ElementUI, {
Vue.use(filters); Vue.use(filters);
Vue.use(ajax); Vue.use(ajax);
// filter
Vue.filter('timestampFormatDate', timestampFormatDate);
// v-permission // v-permission
Vue.directive('permission', permission) Vue.directive('permission', permission)