mirror of
https://gitee.com/fit2cloud-feizhiyun/MeterSphere.git
synced 2024-12-12 13:05:13 +08:00
Merge branch 'master' of https://github.com/metersphere/metersphere
This commit is contained in:
commit
63e234b74b
@ -104,9 +104,8 @@ public class APITestController {
|
||||
|
||||
@PostMapping("/delete")
|
||||
public void delete(@RequestBody DeleteAPITestRequest request) {
|
||||
String testId = request.getId();
|
||||
checkownerService.checkApiTestOwner(testId);
|
||||
apiTestService.delete(testId);
|
||||
checkownerService.checkApiTestOwner(request.getId());
|
||||
apiTestService.delete(request);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/run")
|
||||
|
@ -8,4 +8,8 @@ import lombok.Setter;
|
||||
public class DeleteAPITestRequest {
|
||||
|
||||
private String id;
|
||||
/**
|
||||
* 是否强制删除(删除项目时不检查关联关系,强制删除资源)
|
||||
*/
|
||||
private boolean forceDelete = false;
|
||||
}
|
||||
|
@ -193,8 +193,11 @@ public class APITestService {
|
||||
return extApiTestMapper.getApiTestByProjectId(projectId);
|
||||
}
|
||||
|
||||
public void delete(String testId) {
|
||||
testCaseService.checkIsRelateTest(testId);
|
||||
public void delete(DeleteAPITestRequest request) {
|
||||
String testId = request.getId();
|
||||
if (!request.isForceDelete()) {
|
||||
testCaseService.checkIsRelateTest(testId);
|
||||
}
|
||||
deleteFileByTestId(testId);
|
||||
apiReportService.deleteByTestId(testId);
|
||||
scheduleService.deleteByResourceId(testId);
|
||||
|
@ -3,7 +3,7 @@ package io.metersphere.commons.constants;
|
||||
public enum FileType {
|
||||
JMX(".jmx"), CSV(".csv"), JSON(".json"), PDF(".pdf"),
|
||||
JPG(".jpg"), PNG(".png"), JPEG(".jpeg"), DOC(".doc"),
|
||||
XLSX(".xlsx"), DOCX(".docx");
|
||||
XLSX(".xlsx"), DOCX(".docx"), JAR(".jar");
|
||||
|
||||
// 保存后缀
|
||||
private String suffix;
|
||||
|
@ -28,7 +28,7 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnProperty(prefix="sso",name = "mode", havingValue = "local", matchIfMissing = true)
|
||||
@ConditionalOnProperty(prefix = "sso", name = "mode", havingValue = "local", matchIfMissing = true)
|
||||
public class ShiroConfig implements EnvironmentAware {
|
||||
private Environment env;
|
||||
|
||||
@ -43,6 +43,8 @@ public class ShiroConfig implements EnvironmentAware {
|
||||
shiroFilterFactoryBean.getFilters().put("apikey", new ApiKeyFilter());
|
||||
Map<String, String> filterChainDefinitionMap = shiroFilterFactoryBean.getFilterChainDefinitionMap();
|
||||
ShiroUtils.loadBaseFilterChain(filterChainDefinitionMap);
|
||||
filterChainDefinitionMap.put("/display/info", "anon");
|
||||
filterChainDefinitionMap.put("/display/file/*", "anon");
|
||||
filterChainDefinitionMap.put("/**", "apikey, authc");
|
||||
return shiroFilterFactoryBean;
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ public class MailService {
|
||||
context.put("testCaseName", testCaseWithBLOBs.getName());
|
||||
context.put("description", request.getDescription());
|
||||
context.put("url", baseSystemConfigDTO.getUrl());
|
||||
context.put("id", testCaseWithBLOBs.getId());
|
||||
context.put("id", request.getReviewId());
|
||||
try {
|
||||
String commentTemplate = IOUtils.toString(this.getClass().getResource("/mail/ReviewComments.html"), StandardCharsets.UTF_8);
|
||||
sendReviewNotice(addresseeIdList(messageDetail, userIds, eventType), context, commentTemplate);
|
||||
|
@ -17,6 +17,7 @@ public class EngineContext {
|
||||
private Map<String, Object> properties = new HashMap<>();
|
||||
private Map<String, String> testData = new HashMap<>();
|
||||
private Map<String, String> env = new HashMap<>();
|
||||
private Map<String, byte[]> testJars = new HashMap<>();
|
||||
|
||||
public String getTestId() {
|
||||
return testId;
|
||||
@ -126,4 +127,13 @@ public class EngineContext {
|
||||
public void setResourceIndex(Integer resourceIndex) {
|
||||
this.resourceIndex = resourceIndex;
|
||||
}
|
||||
|
||||
|
||||
public Map<String, byte[]> getTestJars() {
|
||||
return testJars;
|
||||
}
|
||||
|
||||
public void setTestJars(Map<String, byte[]> testJars) {
|
||||
this.testJars = testJars;
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ public class EngineFactory {
|
||||
});
|
||||
|
||||
List<FileMetadata> csvFiles = fileMetadataList.stream().filter(f -> StringUtils.equalsIgnoreCase(f.getType(), FileType.CSV.name())).collect(Collectors.toList());
|
||||
List<FileMetadata> jarFiles = fileMetadataList.stream().filter(f -> StringUtils.equalsIgnoreCase(f.getType(), FileType.JAR.name())).collect(Collectors.toList());
|
||||
final FileContent fileContent = fileService.getFileContent(jmxFile.getId());
|
||||
if (fileContent == null) {
|
||||
MSException.throwException(Translator.get("run_load_test_file_content_not_found") + loadTest.getId());
|
||||
@ -125,6 +126,15 @@ public class EngineFactory {
|
||||
engineContext.setTestData(data);
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(jarFiles)) {
|
||||
Map<String, byte[]> data = new HashMap<>();
|
||||
jarFiles.forEach(jf -> {
|
||||
FileContent content = fileService.getFileContent(jf.getId());
|
||||
data.put(jf.getName(), content.getFile());
|
||||
});
|
||||
engineContext.setTestJars(data);
|
||||
}
|
||||
|
||||
return engineContext;
|
||||
}
|
||||
|
||||
|
@ -83,6 +83,7 @@ public class DockerTestEngine extends AbstractEngine {
|
||||
testRequest.setFileString(content);
|
||||
testRequest.setImage(JMETER_IMAGE);
|
||||
testRequest.setTestData(context.getTestData());
|
||||
testRequest.setTestJars(context.getTestJars());
|
||||
testRequest.setEnv(context.getEnv());
|
||||
|
||||
|
||||
|
@ -14,4 +14,5 @@ public class TestRequest extends BaseRequest {
|
||||
private String image;
|
||||
private Map<String, String> testData = new HashMap<>();
|
||||
private Map<String, String> env = new HashMap<>();
|
||||
private Map<String, byte[]> testJars = new HashMap<>();
|
||||
}
|
||||
|
@ -47,27 +47,26 @@ public class PerformanceNoticeTask {
|
||||
}
|
||||
|
||||
public void registerNoticeTask(LoadTestReportWithBLOBs loadTestReport) {
|
||||
executorService.submit(() -> {
|
||||
while (isRunning) {
|
||||
LoadTestReportWithBLOBs loadTestReportFromDatabase = loadTestReportMapper.selectByPrimaryKey(loadTestReport.getId());
|
||||
|
||||
if (StringUtils.equals(loadTestReportFromDatabase.getStatus(), PerformanceTestStatus.Completed.name())) {
|
||||
isRunning = false;
|
||||
sendSuccessNotice(loadTestReportFromDatabase);
|
||||
return;
|
||||
}
|
||||
if (StringUtils.equals(loadTestReportFromDatabase.getStatus(), PerformanceTestStatus.Error.name())) {
|
||||
isRunning = false;
|
||||
sendFailNotice(loadTestReportFromDatabase);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(1000 * 60);// 每分钟检查 loadtest 的状态
|
||||
} catch (InterruptedException e) {
|
||||
LogUtil.error(e);
|
||||
}
|
||||
int count = 20;
|
||||
while (count-- > 0) {
|
||||
LoadTestReportWithBLOBs loadTestReportFromDatabase = loadTestReportMapper.selectByPrimaryKey(loadTestReport.getId());
|
||||
if (StringUtils.equals(loadTestReportFromDatabase.getStatus(), PerformanceTestStatus.Completed.name())) {
|
||||
isRunning = false;
|
||||
sendSuccessNotice(loadTestReportFromDatabase);
|
||||
return;
|
||||
}
|
||||
});
|
||||
if (StringUtils.equals(loadTestReportFromDatabase.getStatus(), PerformanceTestStatus.Error.name())) {
|
||||
isRunning = false;
|
||||
sendFailNotice(loadTestReportFromDatabase);
|
||||
return;
|
||||
}
|
||||
count--;
|
||||
try {
|
||||
Thread.sleep(1000 * 4L);// 每分钟检查 loadtest 的状态
|
||||
} catch (InterruptedException e) {
|
||||
LogUtil.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void sendSuccessNotice(LoadTestReportWithBLOBs loadTestReport) {
|
||||
|
@ -85,7 +85,9 @@ public class PerformanceTestService {
|
||||
public void delete(DeleteTestPlanRequest request) {
|
||||
String testId = request.getId();
|
||||
|
||||
testCaseService.checkIsRelateTest(testId);
|
||||
if (!request.isForceDelete()) {
|
||||
testCaseService.checkIsRelateTest(testId);
|
||||
}
|
||||
|
||||
LoadTestReportExample loadTestReportExample = new LoadTestReportExample();
|
||||
loadTestReportExample.createCriteria().andTestIdEqualTo(testId);
|
||||
|
@ -14,6 +14,7 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
import javax.annotation.Resource;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
@ -141,4 +142,12 @@ public class FileService {
|
||||
example.createCriteria().andIdIn(fileIds);
|
||||
return fileMetadataMapper.selectByExample(example);
|
||||
}
|
||||
|
||||
public void deleteFileById(String fileId) {
|
||||
deleteFileByIds(Collections.singletonList(fileId));
|
||||
}
|
||||
|
||||
public FileMetadata getFileMetadataById(String fileId) {
|
||||
return fileMetadataMapper.selectByPrimaryKey(fileId);
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package io.metersphere.service;
|
||||
|
||||
import io.metersphere.api.dto.DeleteAPITestRequest;
|
||||
import io.metersphere.api.dto.QueryAPITestRequest;
|
||||
import io.metersphere.api.service.APITestService;
|
||||
import io.metersphere.base.domain.LoadTest;
|
||||
@ -96,6 +97,7 @@ public class ProjectService {
|
||||
loadTestIdList.forEach(loadTestId -> {
|
||||
DeleteTestPlanRequest deleteTestPlanRequest = new DeleteTestPlanRequest();
|
||||
deleteTestPlanRequest.setId(loadTestId);
|
||||
deleteTestPlanRequest.setForceDelete(true);
|
||||
performanceTestService.delete(deleteTestPlanRequest);
|
||||
});
|
||||
|
||||
@ -122,7 +124,10 @@ public class ProjectService {
|
||||
QueryAPITestRequest request = new QueryAPITestRequest();
|
||||
request.setProjectId(projectId);
|
||||
apiTestService.list(request).forEach(test -> {
|
||||
apiTestService.delete(test.getId());
|
||||
DeleteAPITestRequest deleteAPITestRequest = new DeleteAPITestRequest();
|
||||
deleteAPITestRequest.setId(test.getId());
|
||||
deleteAPITestRequest.setForceDelete(true);
|
||||
apiTestService.delete(deleteAPITestRequest);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -73,8 +73,14 @@ public class TestResourcePoolService {
|
||||
LoadTestExample example = new LoadTestExample();
|
||||
example.createCriteria()
|
||||
.andTestResourcePoolIdEqualTo(testResourcePoolId);
|
||||
if (loadTestMapper.countByExample(example) > 0) {
|
||||
MSException.throwException(Translator.get("test_resource_pool_is_use"));
|
||||
List<LoadTest> loadTests = loadTestMapper.selectByExample(example);
|
||||
StringBuilder loadTestNames = new StringBuilder();
|
||||
if (loadTests.size() > 0) {
|
||||
for (LoadTest loadTest : loadTests) {
|
||||
loadTestNames = loadTestNames.append(loadTest.getName()).append(",");
|
||||
}
|
||||
String str = loadTestNames.substring(0, loadTestNames.length() - 1);
|
||||
MSException.throwException(Translator.get("load_test") + " " + str + " " + Translator.get("test_resource_pool_is_use"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,13 @@
|
||||
package io.metersphere.track.request.testplan;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class DeleteTestPlanRequest extends TestPlanRequest {
|
||||
/**
|
||||
* 是否强制删除(删除项目时不检查关联关系,强制删除资源)
|
||||
*/
|
||||
private boolean forceDelete = false;
|
||||
}
|
||||
|
@ -7,5 +7,6 @@ import lombok.Setter;
|
||||
@Getter
|
||||
@Setter
|
||||
public class SaveCommentRequest extends TestCaseComment {
|
||||
private String reviewId;
|
||||
|
||||
}
|
||||
|
@ -546,7 +546,7 @@ public class TestCaseService {
|
||||
for (TestCase testCase : testCases) {
|
||||
caseName = caseName.append(testCase.getName()).append(",");
|
||||
}
|
||||
String str = caseName.toString().substring(0, caseName.length() - 1);
|
||||
String str = caseName.substring(0, caseName.length() - 1);
|
||||
MSException.throwException(Translator.get("related_case_del_fail_prefix") + " " + str + " " + Translator.get("related_case_del_fail_suffix"));
|
||||
}
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit ee74568be0beba46da19616f5832e83f9164c688
|
||||
Subproject commit 24047fea950a74f7848a9fdaa857a22b884c4ce2
|
@ -57,7 +57,8 @@ workspace_not_exists=Workspace is not exists
|
||||
test_resource_pool_id_is_null=Test Resource Pool ID cannot be null
|
||||
test_resource_pool_name_is_null=Test Resource Pool name cannot be null
|
||||
test_resource_pool_name_already_exists=The test resource pool name already exists
|
||||
test_resource_pool_is_use=The test resource pool is in use and cannot be deleted
|
||||
load_test=Load Test
|
||||
test_resource_pool_is_use=This resource pool is in use and cannot be deleted
|
||||
#project
|
||||
project_name_is_null=Project name cannot be null
|
||||
project_name_already_exists=The project name already exists
|
||||
|
@ -57,7 +57,8 @@ workspace_not_exists=工作空间不存在
|
||||
test_resource_pool_id_is_null=资源池ID不能为空
|
||||
test_resource_pool_name_is_null=资源池名称不能为空
|
||||
test_resource_pool_name_already_exists=资源池名称已存在
|
||||
test_resource_pool_is_use=资源池正在使用中,无法删除
|
||||
load_test=性能测试
|
||||
test_resource_pool_is_use=正在使用此资源池,无法删除
|
||||
#project
|
||||
project_name_is_null=项目名称不能为空
|
||||
project_name_already_exists=项目名称已存在
|
||||
|
@ -57,7 +57,8 @@ workspace_not_exists=工作空間不存在
|
||||
test_resource_pool_id_is_null=資源池ID不能為空
|
||||
test_resource_pool_name_is_null=資源池名稱不能為空
|
||||
test_resource_pool_name_already_exists=資源池名稱已存在
|
||||
test_resource_pool_is_use=資源池正在使用中,無法刪除
|
||||
load_test=性能測試
|
||||
test_resource_pool_is_use=正在使用此資源池,無法刪除
|
||||
#project
|
||||
project_name_is_null=項目名稱不能為空
|
||||
project_name_already_exists=項目名稱已存在
|
||||
|
@ -10,7 +10,7 @@
|
||||
${testCaseName}<br/>
|
||||
添加评论:${description}<br/>
|
||||
点击下面链接进入用例评审页面</p>
|
||||
<a href="${url}/#/track/review/view">${url}/#/track/review/view</a>
|
||||
<a href="${url}/#/track/review/view/${id}">${url}/#/track/review/view/${id}</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1215,7 +1215,7 @@ view.results.tree.renderers_order=.RenderAsText,.RenderAsRegexp,.RenderAsBoundar
|
||||
# All entries will be added to the class path of the system class loader
|
||||
# and also to the path of the JMeter internal loader.
|
||||
# Paths with spaces may cause problems for the JVM
|
||||
#user.classpath=../classes;../lib
|
||||
user.classpath=/test/
|
||||
|
||||
# List of directories (separated by ;) that JMeter will search for utility
|
||||
# and plugin dependency classes.
|
||||
|
@ -7,7 +7,8 @@
|
||||
</el-row>
|
||||
<el-row id="header-top" type="flex" justify="space-between" align="middle">
|
||||
<el-col :span="12">
|
||||
<a class="logo"/>
|
||||
<img v-if="logoId" :src="'/display/file/' + logoId" style="width: 156px;height: 37px;" alt="">
|
||||
<a v-else class="logo"/>
|
||||
<ms-top-menus/>
|
||||
</el-col>
|
||||
|
||||
@ -24,107 +25,113 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsTopMenus from "./components/common/head/HeaderTopMenus";
|
||||
import MsView from "./components/common/router/View";
|
||||
import MsUser from "./components/common/head/HeaderUser";
|
||||
import MsHeaderOrgWs from "./components/common/head/HeaderOrgWs";
|
||||
import MsLanguageSwitch from "./components/common/head/LanguageSwitch";
|
||||
import {saveLocalStorage} from "../common/js/utils";
|
||||
import MsTopMenus from "./components/common/head/HeaderTopMenus";
|
||||
import MsView from "./components/common/router/View";
|
||||
import MsUser from "./components/common/head/HeaderUser";
|
||||
import MsHeaderOrgWs from "./components/common/head/HeaderOrgWs";
|
||||
import MsLanguageSwitch from "./components/common/head/LanguageSwitch";
|
||||
import {saveLocalStorage} from "@/common/js/utils";
|
||||
|
||||
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
|
||||
const header = requireComponent.keys().length > 0 ? requireComponent("./license/LicenseMessage.vue") : {};
|
||||
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
|
||||
const header = requireComponent.keys().length > 0 ? requireComponent("./license/LicenseMessage.vue") : {};
|
||||
const display = requireComponent.keys().length > 0 ? requireComponent("./display/Display.vue") : {};
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
licenseHeader: null,
|
||||
auth: false,
|
||||
header: {},
|
||||
}
|
||||
},
|
||||
beforeCreate() {
|
||||
this.$get("/isLogin").then(response => {
|
||||
if (response.data.success) {
|
||||
this.$setLang(response.data.data.language);
|
||||
saveLocalStorage(response.data);
|
||||
this.auth = true;
|
||||
// 是否显示校验信息
|
||||
if (header.default !== undefined) {
|
||||
this.licenseHeader = "LicenseMessage";
|
||||
}
|
||||
} else {
|
||||
window.location.href = "/login"
|
||||
}
|
||||
}).catch(() => {
|
||||
window.location.href = "/login"
|
||||
});
|
||||
},
|
||||
components: {
|
||||
MsLanguageSwitch,
|
||||
MsUser,
|
||||
MsView,
|
||||
MsTopMenus,
|
||||
MsHeaderOrgWs,
|
||||
"LicenseMessage": header.default
|
||||
export default {
|
||||
name: 'app',
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
licenseHeader: null,
|
||||
auth: false,
|
||||
header: {},
|
||||
logoId: '_blank',
|
||||
}
|
||||
},
|
||||
beforeCreate() {
|
||||
this.$get("/isLogin").then(response => {
|
||||
if (response.data.success) {
|
||||
this.$setLang(response.data.data.language);
|
||||
saveLocalStorage(response.data);
|
||||
this.auth = true;
|
||||
// 是否显示校验信息
|
||||
if (header.default !== undefined) {
|
||||
this.licenseHeader = "LicenseMessage";
|
||||
}
|
||||
// 是否显示校验信息
|
||||
if (display.default !== undefined) {
|
||||
display.default.valid(this);
|
||||
}
|
||||
} else {
|
||||
window.location.href = "/login"
|
||||
}
|
||||
}).catch(() => {
|
||||
window.location.href = "/login"
|
||||
});
|
||||
},
|
||||
components: {
|
||||
MsLanguageSwitch,
|
||||
MsUser,
|
||||
MsView,
|
||||
MsTopMenus,
|
||||
MsHeaderOrgWs,
|
||||
"LicenseMessage": header.default
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
#header-top {
|
||||
width: 100%;
|
||||
padding: 0 10px;
|
||||
background-color: rgb(44, 42, 72);
|
||||
color: rgb(245, 245, 245);
|
||||
font-size: 14px;
|
||||
}
|
||||
#header-top {
|
||||
width: 100%;
|
||||
padding: 0 10px;
|
||||
background-color: rgb(44, 42, 72);
|
||||
color: rgb(245, 245, 245);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 156px;
|
||||
margin-bottom: 0;
|
||||
border: 0;
|
||||
margin-right: 20px;
|
||||
display: inline-block;
|
||||
line-height: 37px;
|
||||
background-size: 156px 30px;
|
||||
box-sizing: border-box;
|
||||
height: 37px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 50% center;
|
||||
background-image: url("../assets/logo-light-MeterSphere.svg");
|
||||
}
|
||||
.logo {
|
||||
width: 156px;
|
||||
margin-bottom: 0;
|
||||
border: 0;
|
||||
margin-right: 20px;
|
||||
display: inline-block;
|
||||
line-height: 37px;
|
||||
background-size: 156px 30px;
|
||||
box-sizing: border-box;
|
||||
height: 37px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 50% center;
|
||||
background-image: url("../assets/logo-light-MeterSphere.svg");
|
||||
}
|
||||
|
||||
.menus > * {
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
max-width: 180px;
|
||||
white-space: pre;
|
||||
cursor: pointer;
|
||||
line-height: 40px;
|
||||
}
|
||||
.menus > * {
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
max-width: 180px;
|
||||
white-space: pre;
|
||||
cursor: pointer;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
.header-top-menus {
|
||||
display: inline-block;
|
||||
border: 0;
|
||||
}
|
||||
.header-top-menus {
|
||||
display: inline-block;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.menus > a {
|
||||
padding-right: 15px;
|
||||
text-decoration: none;
|
||||
}
|
||||
.menus > a {
|
||||
padding-right: 15px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.align-right {
|
||||
float: right;
|
||||
}
|
||||
.align-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.license-head {
|
||||
height: 30px;
|
||||
background: #BA331B;
|
||||
text-align: center;
|
||||
line-height: 30px;
|
||||
color: white;
|
||||
}
|
||||
.license-head {
|
||||
height: 30px;
|
||||
background: #BA331B;
|
||||
text-align: center;
|
||||
line-height: 30px;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div v-loading="result.loading">
|
||||
<el-upload
|
||||
accept=".jmx,.csv"
|
||||
accept=".jmx,.csv,.jar"
|
||||
drag
|
||||
action=""
|
||||
:limit="fileNumLimit"
|
||||
@ -77,7 +77,7 @@ export default {
|
||||
fileList: [],
|
||||
tableData: [],
|
||||
uploadList: [],
|
||||
fileNumLimit: 5,
|
||||
fileNumLimit: 10,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
@ -197,7 +197,7 @@ export default {
|
||||
return this.fileList;// 表示修改了已经上传的文件列表
|
||||
},
|
||||
validConfig() {
|
||||
let newJmxNum = 0, oldJmxNum = 0, newCsvNum = 0, oldCsvNum = 0;
|
||||
let newJmxNum = 0, oldJmxNum = 0, newCsvNum = 0, oldCsvNum = 0, newJarNum = 0, oldJarNum = 0;
|
||||
if (this.uploadList.length > 0) {
|
||||
this.uploadList.forEach(f => {
|
||||
if (f.name.toLowerCase().endsWith(".jmx")) {
|
||||
@ -206,6 +206,9 @@ export default {
|
||||
if (f.name.toLowerCase().endsWith(".csv")) {
|
||||
newCsvNum++;
|
||||
}
|
||||
if (f.name.toLowerCase().endsWith(".jar")) {
|
||||
newJarNum++;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this.fileList.length > 0) {
|
||||
@ -216,9 +219,12 @@ export default {
|
||||
if (f.name.toLowerCase().endsWith(".csv")) {
|
||||
oldCsvNum++;
|
||||
}
|
||||
if (f.name.toLowerCase().endsWith(".jar")) {
|
||||
oldJarNum++;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (newCsvNum + oldCsvNum > this.fileNumLimit - 1) {
|
||||
if (newCsvNum + oldCsvNum + newJarNum + oldJarNum > this.fileNumLimit - 1) {
|
||||
this.handleExceed();
|
||||
return false;
|
||||
}
|
||||
|
@ -204,7 +204,11 @@ export default {
|
||||
})
|
||||
},
|
||||
removeRowTask(index, data) { //移除
|
||||
data.splice(index, 1)
|
||||
if (!data[index].identification) {
|
||||
data.splice(index, 1)
|
||||
} else {
|
||||
data[index].isSet = false
|
||||
}
|
||||
},
|
||||
deleteRowTask(index, data) { //删除
|
||||
this.result = this.$get("/notice/delete/message/" + data.identification, response => {
|
||||
|
@ -205,7 +205,12 @@ export default {
|
||||
})
|
||||
},
|
||||
removeRowTask(index, data) { //移除
|
||||
data.splice(index, 1)
|
||||
if (!data[index].identification) {
|
||||
data.splice(index, 1)
|
||||
} else {
|
||||
data[index].isSet = false
|
||||
}
|
||||
|
||||
},
|
||||
deleteRowTask(index, data) { //删除
|
||||
this.result = this.$get("/notice/delete/message/" + data.identification, response => {
|
||||
|
@ -196,7 +196,11 @@ export default {
|
||||
})
|
||||
},
|
||||
removeRowTask(index, data) { //移除
|
||||
data.splice(index, 1)
|
||||
if (!data[index].identification) {
|
||||
data.splice(index, 1)
|
||||
} else {
|
||||
data[index].isSet = false
|
||||
}
|
||||
},
|
||||
deleteRowTask(index, data) { //删除
|
||||
this.result = this.$get("/notice/delete/message/" + data.identification, response => {
|
||||
|
@ -210,7 +210,11 @@ export default {
|
||||
})
|
||||
},
|
||||
removeRowTask(index, data) { //移除
|
||||
data.splice(index, 1)
|
||||
if (!data[index].identification) {
|
||||
data.splice(index, 1)
|
||||
} else {
|
||||
data[index].isSet = false
|
||||
}
|
||||
},
|
||||
deleteRowTask(index, data) { //删除
|
||||
this.result = this.$get("/notice/delete/message/" + data.identification, response => {
|
||||
|
@ -211,7 +211,11 @@ export default {
|
||||
})
|
||||
},
|
||||
removeRowTask(index, data) { //移除
|
||||
data.splice(index, 1)
|
||||
if (!data[index].identification) {
|
||||
data.splice(index, 1)
|
||||
} else {
|
||||
data[index].isSet = false
|
||||
}
|
||||
},
|
||||
deleteRowTask(index, data) { //删除
|
||||
this.result = this.$get("/notice/delete/message/" + data.identification, response => {
|
||||
|
@ -32,7 +32,9 @@ export default {
|
||||
component: () => import('@/business/components/settings/system/SystemParameterSetting'),
|
||||
meta: {system: true, title: 'commons.system_parameter_setting'}
|
||||
},
|
||||
...requireContext.keys().map(key => requireContext(key).system),...requireContext.keys().map(key => requireContext(key).license),
|
||||
...requireContext.keys().map(key => requireContext(key).system),
|
||||
...requireContext.keys().map(key => requireContext(key).license),
|
||||
...requireContext.keys().map(key => requireContext(key).display),
|
||||
{
|
||||
path: 'organizationmember',
|
||||
component: () => import('@/business/components/settings/organization/OrganizationMember'),
|
||||
|
@ -295,7 +295,6 @@ export default {
|
||||
this.infoList = resources;
|
||||
},
|
||||
del(row) {
|
||||
window.console.log(row);
|
||||
this.$confirm(this.$t('test_resource_pool.delete_prompt'), this.$t('commons.prompt'), {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
cancelButtonText: this.$t('commons.cancel'),
|
||||
|
@ -368,8 +368,9 @@ export default {
|
||||
}
|
||||
],
|
||||
phone: [
|
||||
{required: true, message: this.$t('user.input_phone'), trigger: 'blur'},
|
||||
{
|
||||
required: false,
|
||||
required: true,
|
||||
pattern: '^1(3|4|5|7|8)\\d{9}$',
|
||||
message: this.$t('user.mobile_number_format_is_incorrect'),
|
||||
trigger: 'blur'
|
||||
|
@ -40,7 +40,8 @@ export default {
|
||||
components: {ReviewCommentItem},
|
||||
props: {
|
||||
caseId: String,
|
||||
comments: Array
|
||||
comments: Array,
|
||||
reviewId:String,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -53,6 +54,7 @@ export default {
|
||||
let comment = {};
|
||||
comment.caseId = this.caseId;
|
||||
comment.description = this.textarea;
|
||||
comment.reviewId=this.reviewId;
|
||||
if (!this.textarea) {
|
||||
this.$warning(this.$t('test_track.comment.description_is_null'));
|
||||
return;
|
||||
|
@ -229,7 +229,7 @@
|
||||
<i class="el-icon-refresh" @click="getComments(testCase)"
|
||||
style="margin-left:10px;font-size: 14px; cursor: pointer"/>
|
||||
</template>
|
||||
<review-comment :comments="comments" :case-id="testCase.caseId" @getComments="getComments"/>
|
||||
<review-comment :comments="comments" :case-id="testCase.caseId" :review-id="testCase.reviewId" @getComments="getComments"/>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</div>
|
||||
|
@ -300,6 +300,7 @@ export default {
|
||||
return path + "/" + this.currentPage + "/" + this.pageSize;
|
||||
},
|
||||
handleEdit(testCase, index) {
|
||||
console.log(testCase)
|
||||
this.isReadOnly = false;
|
||||
if (!checkoutTestManagerOrTestUser()) {
|
||||
this.isReadOnly = true;
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit cc38137a69a0f20fadece9c0f9f50a9468c4ace9
|
||||
Subproject commit b9091a47b197faef77c72b134b7cf604fe3209f0
|
@ -180,6 +180,14 @@ export default {
|
||||
invalid: 'invalid',
|
||||
expired: 'expired',
|
||||
},
|
||||
display: {
|
||||
title: 'Theme',
|
||||
logo: 'System LOGO',
|
||||
loginLogo: 'Picture on the right side of the login page',
|
||||
loginImage: 'Login page upper left corner LOGO',
|
||||
loginTitle: 'Login page prompt information',
|
||||
pageTitle: 'Page Title',
|
||||
},
|
||||
system_config: {
|
||||
base_config: 'Base Config',
|
||||
base: {
|
||||
@ -228,7 +236,7 @@ export default {
|
||||
mail: 'mail',
|
||||
nail_robot: 'Nail robot',
|
||||
enterprise_wechat_robot: 'Enterprise wechat robot',
|
||||
notes:'Note: 1. Nail and create a custom robot in the enterprise group, and then copy the webhook address on our platform;\n' +
|
||||
notes: 'Note: 1. Nail and create a custom robot in the enterprise group, and then copy the webhook address on our platform;\n' +
|
||||
'\n' +
|
||||
'2. Robots are selected as swarm robots, and "custom keyword" is selected for security verification: "task notification";\n' +
|
||||
'\n' +
|
||||
@ -389,7 +397,7 @@ export default {
|
||||
file_status: 'File Status',
|
||||
last_modify_time: 'Modify time',
|
||||
upload_tips: 'Drag files here, or <em> click to upload </em>',
|
||||
upload_type: 'Only JMX/CSV files can be uploaded',
|
||||
upload_type: 'Only JMX/CSV/JAR files can be uploaded',
|
||||
related_file_not_found: "No related test file found!",
|
||||
delete_file_confirm: 'Confirm delete file:',
|
||||
file_size_limit: "The number of files exceeds the limit!",
|
||||
|
@ -180,6 +180,14 @@ export default {
|
||||
invalid: '无效',
|
||||
expired: '已过期',
|
||||
},
|
||||
display: {
|
||||
title: '显示设置',
|
||||
logo: '系统 LOGO',
|
||||
loginLogo: '登陆页面右侧图片',
|
||||
loginImage: '登录页左上角 LOGO',
|
||||
loginTitle: '登陆页面提示信息',
|
||||
pageTitle: '页面 Title',
|
||||
},
|
||||
system_config: {
|
||||
base_config: '基本配置',
|
||||
base: {
|
||||
@ -229,7 +237,7 @@ export default {
|
||||
mail: '邮件',
|
||||
nail_robot: '钉钉机器人',
|
||||
enterprise_wechat_robot: '企业微信机器人',
|
||||
notes:'注意:1.钉钉和企业群里新建一个自定义机器人,然后复制 webhook 地址在我们平台上;\n' +
|
||||
notes: '注意:1.钉钉和企业群里新建一个自定义机器人,然后复制 webhook 地址在我们平台上;\n' +
|
||||
' 2.机器人选择为群机器人,安全验证选择“自定义关键词” :"任务通知";\n' +
|
||||
' 3.选择接收人时必须是你所建的群里包含的人,接收人手机号为必填项且为钉钉企业所使用的手机号,',
|
||||
message: '事件,接收人,接收方式为必填项',
|
||||
@ -387,7 +395,7 @@ export default {
|
||||
file_status: '文件状态',
|
||||
last_modify_time: '修改时间',
|
||||
upload_tips: '将文件拖到此处,或<em>点击上传</em>',
|
||||
upload_type: '只能上传JMX/CSV文件',
|
||||
upload_type: '只能上传JMX/CSV/JAR文件',
|
||||
related_file_not_found: "未找到关联的测试文件!",
|
||||
delete_file_confirm: '确认删除文件: ',
|
||||
file_size_limit: "文件个数超出限制!",
|
||||
|
@ -180,6 +180,14 @@ export default {
|
||||
invalid: '無效',
|
||||
expired: '已過期',
|
||||
},
|
||||
display: {
|
||||
title: '顯示設置',
|
||||
logo: '系統 LOGO',
|
||||
loginLogo: '登陸頁面右側圖片',
|
||||
loginImage: '登錄頁左上角 LOGO',
|
||||
loginTitle: '登陸頁面提示信息',
|
||||
pageTitle: '頁面 Title',
|
||||
},
|
||||
system_config: {
|
||||
base_config: '基本配置',
|
||||
base: {
|
||||
@ -389,7 +397,7 @@ export default {
|
||||
file_status: '文件狀態',
|
||||
last_modify_time: '修改時間',
|
||||
upload_tips: '將文件拖到此處,或<em>點擊上傳</em>',
|
||||
upload_type: '只能上傳JMX/CSV文件',
|
||||
upload_type: '只能上傳JMX/CSV/JAR文件',
|
||||
related_file_not_found: "未找到關聯的測試文件!",
|
||||
delete_file_confirm: '確認刪除文件: ',
|
||||
file_size_limit: "文件個數超出限制!",
|
||||
|
@ -4,15 +4,16 @@
|
||||
<el-col :span="12">
|
||||
<el-form :model="form" :rules="rules" ref="form">
|
||||
<div class="logo">
|
||||
<img src="../assets/logo-dark-MeterSphere.svg" style="width: 224px" alt="">
|
||||
<img v-if="loginLogoId" :src="'/display/file/' + loginLogoId" style="width: 224px;height: 45px;" alt="">
|
||||
<img v-else src="../assets/logo-dark-MeterSphere.svg" style="width: 224px; " alt="">
|
||||
</div>
|
||||
<div class="title">
|
||||
<span id="s1">{{$t('commons.login')}}</span>
|
||||
<span id="s1">{{ $t('commons.login') }}</span>
|
||||
<span id="s2">MeterSphere</span>
|
||||
</div>
|
||||
<div class="border"></div>
|
||||
<div class="welcome">
|
||||
{{$t('commons.welcome')}}
|
||||
{{ $t('commons.welcome') }}
|
||||
</div>
|
||||
<div class="form">
|
||||
<el-form-item v-slot:default>
|
||||
@ -32,241 +33,252 @@
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button type="primary" class="submit" @click="submit('form')">
|
||||
{{$t('commons.login')}}
|
||||
{{ $t('commons.login') }}
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="msg">
|
||||
{{msg}}
|
||||
{{ msg }}
|
||||
</div>
|
||||
</el-form>
|
||||
</el-col>
|
||||
<el-col :span="12" class="image">
|
||||
<div></div>
|
||||
<el-col :span="12">
|
||||
<img v-if="loginImageId" :src="'/display/file/' + loginImageId" style="height: 560px; width: 100%">
|
||||
<img v-else src="../assets/info.png" style="height: 560px; width: 100%">
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {saveLocalStorage} from '../common/js/utils';
|
||||
import {DEFAULT_LANGUAGE} from "../common/js/constants";
|
||||
import {saveLocalStorage} from '@/common/js/utils';
|
||||
import {DEFAULT_LANGUAGE} from "@/common/js/constants";
|
||||
|
||||
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
|
||||
const display = requireComponent.keys().length > 0 ? requireComponent("./display/Display.vue") : {};
|
||||
|
||||
export default {
|
||||
name: "Login",
|
||||
data() {
|
||||
/*let validateEmail = (rule, value, callback) => {
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
let EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
if (!EMAIL_REGEX.test(value)) {
|
||||
callback(new Error('邮箱格式不正确'));
|
||||
export default {
|
||||
name: "Login",
|
||||
data() {
|
||||
/*let validateEmail = (rule, value, callback) => {
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
let EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
if (!EMAIL_REGEX.test(value)) {
|
||||
callback(new Error('邮箱格式不正确'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};*/
|
||||
return {
|
||||
result: {},
|
||||
form: {
|
||||
username: '',
|
||||
password: '',
|
||||
authenticate: 'LOCAL'
|
||||
},
|
||||
rules: {
|
||||
username: [
|
||||
{required: true, message: this.$t('commons.input_login_username'), trigger: 'blur'},
|
||||
],
|
||||
password: [
|
||||
{required: true, message: this.$t('commons.input_password'), trigger: 'blur'},
|
||||
{min: 6, max: 20, message: this.$t('commons.input_limit', [6, 20]), trigger: 'blur'}
|
||||
]
|
||||
},
|
||||
msg: '',
|
||||
ready: false,
|
||||
openLdap: false,
|
||||
loginLogoId: '_blank',
|
||||
loginImageId: '_blank',
|
||||
}
|
||||
},
|
||||
beforeCreate() {
|
||||
this.result = this.$get("/isLogin").then(response => {
|
||||
|
||||
if (display.default !== undefined) {
|
||||
display.default.valid(this);
|
||||
}
|
||||
|
||||
if (!response.data.success) {
|
||||
if (response.data.message === 'sso') {
|
||||
window.location.href = "/sso/login"
|
||||
} else {
|
||||
callback();
|
||||
this.ready = true;
|
||||
}
|
||||
};*/
|
||||
return {
|
||||
result: {},
|
||||
form: {
|
||||
username: '',
|
||||
password: '',
|
||||
authenticate: 'LOCAL'
|
||||
},
|
||||
rules: {
|
||||
username: [
|
||||
{required: true, message: this.$t('commons.input_login_username'), trigger: 'blur'},
|
||||
],
|
||||
password: [
|
||||
{required: true, message: this.$t('commons.input_password'), trigger: 'blur'},
|
||||
{min: 6, max: 20, message: this.$t('commons.input_limit', [6, 20]), trigger: 'blur'}
|
||||
]
|
||||
},
|
||||
msg: '',
|
||||
ready: false,
|
||||
openLdap: false
|
||||
} else {
|
||||
let user = response.data.data;
|
||||
saveLocalStorage(response.data);
|
||||
this.getLanguage(user.language);
|
||||
window.location.href = "/"
|
||||
}
|
||||
});
|
||||
this.$get("/ldap/open", response => {
|
||||
this.openLdap = response.data;
|
||||
})
|
||||
},
|
||||
created: function () {
|
||||
// 主页添加键盘事件,注意,不能直接在焦点事件上添加回车
|
||||
document.addEventListener("keydown", this.watchEnter);
|
||||
},
|
||||
|
||||
destroyed() {
|
||||
//移除监听回车按键
|
||||
document.removeEventListener("keydown", this.watchEnter);
|
||||
},
|
||||
methods: {
|
||||
//监听回车按钮事件
|
||||
watchEnter(e) {
|
||||
let keyNum = e.which; //获取被按下的键值
|
||||
//判断如果用户按下了回车键(keycody=13)
|
||||
if (keyNum === 13) {
|
||||
// 按下回车按钮要做的事
|
||||
this.submit('form');
|
||||
}
|
||||
},
|
||||
beforeCreate() {
|
||||
this.$get("/isLogin").then(response => {
|
||||
if (!response.data.success) {
|
||||
if (response.data.message === 'sso') {
|
||||
window.location.href = "/sso/login"
|
||||
} else {
|
||||
this.ready = true;
|
||||
submit(form) {
|
||||
this.$refs[form].validate((valid) => {
|
||||
if (valid) {
|
||||
switch (this.form.authenticate) {
|
||||
case "LOCAL":
|
||||
this.normalLogin();
|
||||
break;
|
||||
case "LDAP":
|
||||
this.ldapLogin();
|
||||
break;
|
||||
default:
|
||||
this.normalLogin();
|
||||
}
|
||||
} else {
|
||||
let user = response.data.data;
|
||||
saveLocalStorage(response.data);
|
||||
this.getLanguage(user.language);
|
||||
window.location.href = "/"
|
||||
return false;
|
||||
}
|
||||
});
|
||||
this.$get("/ldap/open", response => {
|
||||
this.openLdap = response.data;
|
||||
})
|
||||
},
|
||||
created: function () {
|
||||
// 主页添加键盘事件,注意,不能直接在焦点事件上添加回车
|
||||
document.addEventListener("keydown", this.watchEnter);
|
||||
normalLogin() {
|
||||
this.result = this.$post("signin", this.form, response => {
|
||||
saveLocalStorage(response);
|
||||
sessionStorage.setItem('loginSuccess', 'true');
|
||||
this.getLanguage(response.data.language);
|
||||
});
|
||||
},
|
||||
destroyed() {
|
||||
//移除监听回车按键
|
||||
document.removeEventListener("keydown", this.watchEnter);
|
||||
ldapLogin() {
|
||||
this.result = this.$post("ldap/signin", this.form, response => {
|
||||
saveLocalStorage(response);
|
||||
sessionStorage.setItem('loginSuccess', 'true');
|
||||
this.getLanguage(response.data.language);
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
//监听回车按钮事件
|
||||
watchEnter(e) {
|
||||
let keyNum = e.which; //获取被按下的键值
|
||||
//判断如果用户按下了回车键(keycody=13)
|
||||
if (keyNum === 13) {
|
||||
// 按下回车按钮要做的事
|
||||
this.submit('form');
|
||||
}
|
||||
},
|
||||
submit(form) {
|
||||
this.$refs[form].validate((valid) => {
|
||||
if (valid) {
|
||||
switch (this.form.authenticate) {
|
||||
case "LOCAL":
|
||||
this.normalLogin();
|
||||
break;
|
||||
case "LDAP":
|
||||
this.ldapLogin();
|
||||
break;
|
||||
default:
|
||||
this.normalLogin();
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
normalLogin() {
|
||||
this.result = this.$post("signin", this.form, response => {
|
||||
saveLocalStorage(response);
|
||||
sessionStorage.setItem('loginSuccess', 'true');
|
||||
this.getLanguage(response.data.language);
|
||||
});
|
||||
},
|
||||
ldapLogin() {
|
||||
this.result = this.$post("ldap/signin", this.form, response => {
|
||||
saveLocalStorage(response);
|
||||
sessionStorage.setItem('loginSuccess', 'true');
|
||||
this.getLanguage(response.data.language);
|
||||
});
|
||||
},
|
||||
getLanguage(language) {
|
||||
if (!language) {
|
||||
this.$get("language", response => {
|
||||
language = response.data;
|
||||
localStorage.setItem(DEFAULT_LANGUAGE, language);
|
||||
window.location.href = "/"
|
||||
})
|
||||
} else {
|
||||
getLanguage(language) {
|
||||
if (!language) {
|
||||
this.$get("language", response => {
|
||||
language = response.data;
|
||||
localStorage.setItem(DEFAULT_LANGUAGE, language);
|
||||
window.location.href = "/"
|
||||
}
|
||||
})
|
||||
} else {
|
||||
window.location.href = "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
min-width: 800px;
|
||||
max-width: 1440px;
|
||||
height: 560px;
|
||||
margin: calc((100vh - 560px) / 2) auto 0;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
.container {
|
||||
min-width: 800px;
|
||||
max-width: 1440px;
|
||||
height: 560px;
|
||||
margin: calc((100vh - 560px) / 2) auto 0;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
.logo {
|
||||
margin: 30px 30px 0;
|
||||
}
|
||||
.logo {
|
||||
margin: 30px 30px 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-top: 50px;
|
||||
font-size: 32px;
|
||||
letter-spacing: 0;
|
||||
text-align: center;
|
||||
}
|
||||
.title {
|
||||
margin-top: 50px;
|
||||
font-size: 32px;
|
||||
letter-spacing: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.title > #s1 {
|
||||
color: #999999;
|
||||
}
|
||||
.title > #s1 {
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.title > #s2 {
|
||||
color: #151515;
|
||||
}
|
||||
.title > #s2 {
|
||||
color: #151515;
|
||||
}
|
||||
|
||||
.border {
|
||||
height: 2px;
|
||||
margin: 20px auto 20px;
|
||||
position: relative;
|
||||
width: 80px;
|
||||
background: #8B479B;
|
||||
}
|
||||
.border {
|
||||
height: 2px;
|
||||
margin: 20px auto 20px;
|
||||
position: relative;
|
||||
width: 80px;
|
||||
background: #8B479B;
|
||||
}
|
||||
|
||||
.welcome {
|
||||
margin-top: 50px;
|
||||
font-size: 14px;
|
||||
color: #999999;
|
||||
letter-spacing: 0;
|
||||
line-height: 18px;
|
||||
text-align: center;
|
||||
}
|
||||
.welcome {
|
||||
margin-top: 50px;
|
||||
font-size: 14px;
|
||||
color: #999999;
|
||||
letter-spacing: 0;
|
||||
line-height: 18px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.form {
|
||||
margin-top: 30px;
|
||||
padding: 0 40px;
|
||||
}
|
||||
.form {
|
||||
margin-top: 30px;
|
||||
padding: 0 40px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
margin-top: 40px;
|
||||
padding: 0 40px;
|
||||
}
|
||||
.btn {
|
||||
margin-top: 40px;
|
||||
padding: 0 40px;
|
||||
}
|
||||
|
||||
.btn > .submit {
|
||||
width: 100%;
|
||||
border-radius: 0;
|
||||
border-color: #8B479B;
|
||||
background-color: #8B479B;
|
||||
}
|
||||
.btn > .submit {
|
||||
width: 100%;
|
||||
border-radius: 0;
|
||||
border-color: #8B479B;
|
||||
background-color: #8B479B;
|
||||
}
|
||||
|
||||
.btn > .submit:hover {
|
||||
border-color: rgba(139, 71, 155, 0.9);
|
||||
background-color: rgba(139, 71, 155, 0.9);
|
||||
}
|
||||
.btn > .submit:hover {
|
||||
border-color: rgba(139, 71, 155, 0.9);
|
||||
background-color: rgba(139, 71, 155, 0.9);
|
||||
}
|
||||
|
||||
.btn > .submit:active {
|
||||
border-color: rgba(139, 71, 155, 0.8);
|
||||
background-color: rgba(139, 71, 155, 0.8);
|
||||
}
|
||||
.btn > .submit:active {
|
||||
border-color: rgba(139, 71, 155, 0.8);
|
||||
background-color: rgba(139, 71, 155, 0.8);
|
||||
}
|
||||
|
||||
.msg {
|
||||
margin-top: 10px;
|
||||
padding: 0 40px;
|
||||
color: red;
|
||||
text-align: center;
|
||||
}
|
||||
.msg {
|
||||
margin-top: 10px;
|
||||
padding: 0 40px;
|
||||
color: red;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.image {
|
||||
background: url(../assets/info.png);
|
||||
height: 560px;
|
||||
}
|
||||
.image {
|
||||
background: url(../assets/info.png);
|
||||
height: 560px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Neue Haas Grotesk Text Pro", "Arial Nova", "Segoe UI", "Helvetica Neue", ".PingFang SC", "PingFang SC", "Source Han Sans SC", "Noto Sans CJK SC", "Source Han Sans CN", "Noto Sans SC", "Source Han Sans TC", "Noto Sans CJK TC", "Hiragino Sans GB", sans-serif;
|
||||
font-size: 14px;
|
||||
background-color: #F5F5F5;
|
||||
line-height: 26px;
|
||||
color: #2B415C;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
margin: 0;
|
||||
}
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Neue Haas Grotesk Text Pro", "Arial Nova", "Segoe UI", "Helvetica Neue", ".PingFang SC", "PingFang SC", "Source Han Sans SC", "Noto Sans CJK SC", "Source Han Sans CN", "Noto Sans SC", "Source Han Sans TC", "Noto Sans CJK TC", "Hiragino Sans GB", sans-serif;
|
||||
font-size: 14px;
|
||||
background-color: #F5F5F5;
|
||||
line-height: 26px;
|
||||
color: #2B415C;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.form .el-input > .el-input__inner {
|
||||
border-radius: 0;
|
||||
}
|
||||
.form .el-input > .el-input__inner {
|
||||
border-radius: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user