add:性能测试-测试

This commit is contained in:
fanzhuxian
2025-04-17 10:55:01 +08:00
parent adbceebec5
commit 87bb3af12c
7 changed files with 1094 additions and 5 deletions

View File

@@ -0,0 +1,63 @@
import request from '@/utils/request'
// 测试-列表查询
export function getPerfromanceList(query) {
return request({
url: '/test/performanceTest/list',
method: 'get',
params: query
})
}
// 测试-列表删除
export function deleteTest(data) {
return request({
url: '/test/performanceTest/' + data,
method: 'put',
data: data
})
}
// 测试-列表新增
export function addTest(data) {
return request({
url: '/test/performanceTest/add',
method: 'post',
data: data
})
}
// 测试-列表新增并执行
export function addAndExecuteTest(data) {
return request({
url: '/test/performanceTest/addAndExecute',
method: 'post',
data: data
})
}
// 引用接口自动化场景
export function getTestCaseList(query) {
return request({
url: '/test/performanceTest/testCaseList',
method: 'get',
params: query
})
}
//测试-编辑
export function editTest(data) {
return request({
url: '/test/performanceTest',
method: 'put',
data: data
})
}
//测试-编辑-保存并执行
export function editAndExecuteTest(data) {
return request({
url: '/test/performanceTest/editAndExecute',
method: 'put',
data: data
})
}

View File

@@ -144,6 +144,34 @@ export const constantRoutes = [
}
]
},
{
path: '/performance/add',
component: Layout,
hidden: true,
children: [
{
path: '',
component: () => import('@/views/test/performance/performanceAdd'),
name: 'performanceAdd',
noCache: true,
meta: { title: '新增测试', activeMenu: '/performance' }
}
]
},
{
path: '/performance/edit',
component: Layout,
hidden: true,
children: [
{
path: '',
component: () => import('@/views/test/performance/performanceEdit'),
name: 'performanceAdd',
noCache: true,
meta: { title: '修改测试', activeMenu: '/performance' }
}
]
},
]
// 动态路由,基于用户权限动态去加载

View File

@@ -1,11 +1,138 @@
<script setup>
<template>
<div class="performance">
<div class="header">
<el-button icon="el-icon-circle-plus-outline" @click="addTest">创建测试</el-button>
<div class="search">
<el-input v-model="serachForm.performanceName" placeholder="根据名称搜索"></el-input>
<el-button type="text" style="margin-left: 10px;" @click="serachList">高级搜索</el-button>
</div>
</div>
<el-divider></el-divider>
<div class="table">
<el-table :data="data">
<el-table-column type="selection" width="55" />
<el-table-column prop="id" label="ID" width="50" align="center" />
<el-table-column prop="performanceName" label="名称" width="150" align="center" />
<el-table-column prop="createBy" label="创建人" width="100" sortable align="center" />
<el-table-column prop="createTime" label="创建时间" sortable align="center" />
<el-table-column prop="updateTime" label="更新时间" sortable align="center" />
<el-table-column prop="status" label="状态" width="50" align="center">
<template slot-scope="scope">
<div v-if="scope.row.status === '0'"></div>
<div v-else></div>
</template>
</el-table-column>
<el-table-column prop="action" label="操作" align="center">
<template slot-scope="scope">
<el-button type="text" icon="el-icon-edit-outline" @click="hadleClickEdit(scope.row)">编辑</el-button>
<el-button type="text" icon="el-icon-delete" style="color: red;"
@click="hadleClickDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="page">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange"
:page-size="serachForm.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total" />
</div>
</div>
</div>
</template>
<script>
import { getPerfromanceList, deleteTest } from '../../../api/performance'
export default {
name: "Performance",
data() {
return {
data: [],
serachForm: {
pageNum: 1,
pageSize: 10,
performanceName: '', // 名称
},
total: 0,
}
},
mounted() {
this.getPerformaceData()
},
methods: {
// 创建测试
addTest() {
this.$tab.openPage("新增测试", "/performance/add");
},
// 高级搜索
serachList() {
this.getPerformaceData()
},
// 编辑
hadleClickEdit(val) {
this.$tab.openPage("修改测试", "/performance/edit", { data: val });
},
// 删除
hadleClickDelete(val) {
deleteTest(String(val.id)).then(res => {
if (res.code === 200) {
this.$message({ message: '删除成功', type: 'success' })
this.getPerformaceData()
} else {
this.$message({ message: '删除失败', type: 'error' })
}
})
},
// 分页
handleSizeChange(val) {
this.serachForm.pageSize = val
this.getPerformaceData()
},
handleCurrentChange(val) {
this.serachForm.pageNum = val
this.getPerformaceData()
},
// networking
// 获取测试列表
getPerformaceData() {
getPerfromanceList(this.serachForm).then(res => {
if (res.code === 200) {
this.data = res.rows
this.total = res.total
}
})
},
}
}
</script>
<template>
<p>性能</p>
</template>
<style scoped lang="scss">
.performance {
padding: 10px;
.header {
display: flex;
justify-content: space-between;
padding: 10px;
}
.search {
display: flex;
}
.page {
padding: 10px;
display: flex;
justify-content: flex-end;
}
}
::v-deep .el-divider--horizontal {
display: block;
height: 1px;
width: 100%;
margin: 10px 0;
}
</style>

View File

@@ -0,0 +1,431 @@
<template>
<div class="performanceAdd">
<div class="header">
<div class="name">
<div class="name-wrap">测试名称</div>
<el-input v-model="addForm.performanceName" placeholder="请输入名称" maxlength="255" show-word-limit></el-input>
</div>
<div class="save">
<el-button type="primary" plain @click="handleWithSave">保存</el-button>
<el-button type="primary" plain @click="handleWithSaveAndExecute">保存并执行</el-button>
<el-button type="warning" plain @click="handleWithCancel">取消</el-button>
</div>
<div class="date">
<div class="date-top">
<i class="el-icon-date"></i>
<span class="date-title">SCHEDULER</span>
<el-switch v-model="switchOpen" @change="switchChange"></el-switch>
</div>
<div class="date-bottom">
<span>下次执行时间</span>
</div>
</div>
</div>
<div class="tab">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="场景配置" name="first">
<div class="title">场景列表</div>
<el-button style="margin-top: 10px; margin-bottom: 10px;" icon="el-icon-share"
@click="handleClickLoad">引用接口自动化场景</el-button>
<el-table :data="changeList">
<el-table-column prop="name" label="场景名称" />
<el-table-column prop="status" label="Enable/Disable" />
<el-table-column prop="action" label="操作">
<template slot-scope="scope">
<el-button type="text" icon="el-icon-delete" style="color: red;"
@click="hadleClickDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="压力配置" name="second">
<div class="pressure-header">
<div class="title">速兑通接口</div>
<div class="pressure-title">并发用户数{{ addForm.concurrentThreads }}压测时长{{ addForm.pressureHour }}{{
addForm.pressureMinute }}{{ addForm.pressureSecond }}</div>
</div>
<div class="pressure-wrap">
<div class="pressure-warap-name">并发用户数</div>
<el-input-number v-model="addForm.concurrentThreads" controls-position="right" :min="0"></el-input-number>
</div>
<div class="pressure-wrap">
<div class="pressure-warap-name">取样器错误后</div>
<el-select v-model="addForm.errorOperType" placeholder="请选择">
<el-option key="1" label="继续" value="1"></el-option>
<el-option key="2" label="开始下一个线程轮询" value="2"></el-option>
<el-option key="3" label="停止线程" value="3"></el-option>
<el-option key="4" label="停止测试" value="4"></el-option>
<el-option key="5" label="立即停止测试" value="5"></el-option>
</el-select>
</div>
<div class="pressure-wrap">
<div class="pressure-warap-name">执行方式</div>
<el-radio-group v-model="addForm.executeType">
<el-radio-button :label="1">按持续时间</el-radio-button>
<el-radio-button :label="2">按迭代次数</el-radio-button>
</el-radio-group>
<el-input-number v-if="addForm.executeType === 2" style="margin-left: 10px;" v-model="addForm.loopCount"
controls-position="right" :min="0"></el-input-number>
</div>
<div class="pressure-wrap">
<div class="pressure-warap-name">Ramp-Up</div>
<el-input-number v-model="addForm.rampUpSeconds" controls-position="right" :min="0"></el-input-number>
<div class="pressure-warap-name"></div>
</div>
<div class="pressure-wrap">
<div class="pressure-warap-name">压测时长</div>
<el-input-number v-model="addForm.pressureHour" controls-position="right" :min="0"></el-input-number>
<div class="pressure-warap-name"></div>
<el-input-number v-model="addForm.pressureMinute" controls-position="right" :min="0"></el-input-number>
<div class="pressure-warap-name"></div>
<el-input-number v-model="addForm.pressureSecond" controls-position="right" :min="0"></el-input-number>
<div class="pressure-warap-name"></div>
</div>
<div class="pressure-wrap">
<div class="pressure-warap-name">Rps开启</div>
<el-switch v-model="addForm.rpsStatus" active-value="1" inactive-value="0"></el-switch>
<div class="pressure-warap-name">Rps上限</div>
<el-input-number v-model="addForm.rpsLimit" controls-position="right" :min="0"></el-input-number>
</div>
</el-tab-pane>
</el-tabs>
</div>
<el-dialog title="场景列表" :visible.sync="dialogVisible" width="60%">
<div class="search">
<el-input v-model="searchScenen.name" style="width: 300px;" placeholder="根据ID/名称/标签 搜索"
@blur="searchSecenList"></el-input>
</div>
<div class="table">
<el-table ref="tableRef" :data="sceneList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column prop="id" width="100" label="ID" align="center" />
<el-table-column prop="name" label="场景名称" align="center" />
<el-table-column prop="remark" label="标签" align="center" />
<el-table-column prop="createTime" label="修改时间" align="center" />
</el-table>
<div class="page">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange"
:page-size="searchScenen.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="totalScene" />
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="handleWithSure"> </el-button>
</span>
</el-dialog>
<el-dialog title="定时任务" :visible.sync="dialogVisibleTime" width="60%" :before-close="handleClose">
<el-tabs v-model="activeTime">
<el-tab-pane label="任务配置" name="first"></el-tab-pane>
<div class="editTimeTitle">编辑定时任务</div>
<div class="crontab-wrap">
<div class="title">Crontab表达式</div>
<el-input v-model="addForm.crontab" @input="updateExecutionTimes" placeholder="请输入crontab表达式" />
<div class="title" style="margin-left: 50px;">定时任务开关</div>
<el-switch v-model="addForm.crontabStatus" active-value="1" inactive-value="0"></el-switch>
</div>
<div class="near-time">
<div class="title">最近5次运行时间</div>
<div v-for="(item, index) in executionTimeList" :key="index">
{{ item.time }}
</div>
</div>
</el-tabs>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisibleTime = false, switchOpen = false"> </el-button>
<el-button type="primary" @click="dialogVisibleTime = false"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { addTest, addAndExecuteTest, getTestCaseList } from '../../../api/performance';
export default {
name: "PerformanceAdd",
data() {
return {
addForm: {
performanceName: '', // 性能测试名称
performanceTestCaseVOList: [], // 场景列表
concurrentThreads: '', // 并发用户数
errorOperType: '', // 在取样器错误后要执行的动作1继续2开始下一个线程轮询3停止线程4停止测试5立即停止测试
executeType: '', // 执行方式1按持续时间2按迭代次数
rampUpSeconds: '0', // 多少秒内线程建立完成默认0
pressureHour: '0', // 压测时长默认0
pressureMinute: '0', // 压测时长默认0
pressureSecond: '0', // 压测时长默认0
rpsStatus: '0', // rps状态0关闭1开启默认0
rpsLimit: '0', // 每分钟rps上限数默认0
crontab: '', // crontab表达式
crontabStatus: '0', // 定时任务状态0关闭1开启默认0
loopCount: '0', // 迭代次数默认0
},
activeName: 'first',
sceneList: [], // 场景列表
dialogVisible: false, // 场景列表
searchScenen: {
pageNum: 1,
pageSize: 10,
name: '', // 名称
},
totalScene: 0,
searchScene: '',
changeList: [],
multipleSelection: [],
switchOpen: false,
dialogVisibleTime: false,
activeTime: 'first',
executionTimeList: [
{
time: "2025-02-18 10:00:00",
},
{
time: "2025-02-19 10:00:00",
},
{
time: "2025-02-20 10:00:00",
},
{
time: "2025-02-21 10:00:00",
},
{
time: "2025-02-22 10:00:00",
},
],
}
},
mounted() {
this.getTestCaseData()
},
methods: {
// 保存
handleWithSave() {
this.changeList.forEach(item => {
var par = {
testCaseId: item.id,
status: item.status
}
this.addForm.performanceTestCaseVOList.push(par)
})
console.log(this.addForm)
addTest(this.addForm).then(res => {
if (res.code === 200) {
this.$message({ message: '新增成功', type: 'success' })
this.$tab.closeOpenPage({ path: "/performance/performance" });
} else {
this.$message({ message: '新增失败', type: 'error' })
}
})
},
// 保存并执行
handleWithSaveAndExecute() {
addAndExecuteTest(this.addForm).then(res => {
if (res.code === 200) {
this.$message({ message: '新增成功', type: 'success' })
this.$tab.closeOpenPage({ path: "/performance/performance" });
} else {
this.$message({ message: '新增失败', type: 'error' })
}
})
},
// 取消
handleWithCancel() {
this.$tab.closeOpenPage({ path: "/performance/performance" });
},
handleClick() { },
// 加载jmx文件
handleClickLoad() {
this.dialogVisible = true
},
// 删除
hadleClickDelete(val) {
this.changeList = this.changeList.filter(item => item !== val);
this.multipleSelection = this.multipleSelection.filter(item => item !== val);
this.sceneList.forEach(row => {
if (this.multipleSelection.includes(row)) {
this.$refs.tableRef.toggleRowSelection(row, true);
} else {
this.$refs.tableRef.toggleRowSelection(row, false);
}
})
},
// netWorking
getTestCaseData() {
getTestCaseList(this.searchScenen).then(res => {
if (res.code === 200) {
this.sceneList = res.rows
}
})
},
searchSecenList() {
this.getTestCaseData()
},
// 分页
handleSizeChange(val) {
this.searchScenen.pageSize = val
this.getTestCaseData()
},
handleCurrentChange(val) {
this.searchScenen.pageNum = val
this.getTestCaseData()
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
handleWithSure() {
this.changeList = this.multipleSelection
this.dialogVisible = false
},
switchChange(val) {
this.dialogVisibleTime = val
},
handleClose() {
this.dialogVisibleTime = false
this.switchOpen = false
},
// 根据crontab表达式更新执行时间
updateExecutionTimes() {
const crontab = this.addForm.crontab.trim();
if (!crontab) {
this.executionTimeList = [];
return;
}
try {
// 解析crontab表达式
const interval = cronParser.parseExpression(crontab);
const times = [];
// 获取最近三次执行时间
for (let i = 0; i < 3; i++) {
const nextTime = interval.next().toDate(); // 获取 Date 对象
const formattedTime = this.formatDate(nextTime); // 格式化时间
times.push({ time: formattedTime });
}
this.executionTimeList = times;
} catch (error) {
console.error('无效的crontab表达式:', error);
this.executionTimeList = [{ time: '无效的crontab表达式' }];
}
},
}
}
</script>
<style scoped lang="scss">
.performanceAdd {
padding: 20px;
.header {
display: flex;
justify-content: space-between;
.name {
display: flex;
width: 300px;
align-items: center;
.name-wrap {
width: 80px;
font-size: 14px;
}
}
}
.tab {
margin-top: 20px;
.title {
font-size: 14px;
font-weight: 600;
}
}
.search {
display: flex;
justify-content: flex-end;
margin-bottom: 10px;
}
.page {
padding: 10px;
display: flex;
justify-content: flex-end;
}
.pressure-header {
display: flex;
align-items: center;
margin-bottom: 10px;
.pressure-title {
margin-left: 20px;
font-size: 12px;
font-weight: 500;
}
}
.pressure-wrap {
display: flex;
padding: 10px;
align-items: center;
.pressure-warap-name {
font-size: 14px;
font-weight: 400;
margin: 0px 10px;
}
}
.date {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.date-top {
display: flex;
.date-title {
font-size: 14px;
font-weight: 500;
margin: 0px 10px;
}
}
.date-bottom {
display: flex;
margin: 10px;
}
}
.editTimeTitle {
font-size: 14px;
font-weight: 500;
margin-bottom: 10px;
}
.crontab-wrap {
display: flex;
align-items: center;
.title {
font-size: 14px;
width: 150px;
margin-right: 20px;
}
}
.near-time {
margin-top: 20px;
padding: 20px 10px;
border: solid #dcdfe6 1px;
}
}
</style>

View File

@@ -0,0 +1,431 @@
<template>
<div class="performanceAdd">
<div class="header">
<div class="name">
<div class="name-wrap">测试名称</div>
<el-input v-model="addForm.performanceName" placeholder="请输入名称" maxlength="255" show-word-limit></el-input>
</div>
<div class="save">
<el-button type="primary" plain @click="handleWithSave">保存</el-button>
<el-button type="primary" plain @click="handleWithSaveAndExecute">保存并执行</el-button>
<el-button type="warning" plain @click="handleWithCancel">取消</el-button>
</div>
<div class="date">
<div class="date-top">
<i class="el-icon-date"></i>
<span class="date-title">SCHEDULER</span>
<el-switch v-model="switchOpen" @change="switchChange"></el-switch>
</div>
<div class="date-bottom">
<span>下次执行时间</span>
</div>
</div>
</div>
<div class="tab">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="场景配置" name="first">
<div class="title">场景列表</div>
<el-button style="margin-top: 10px; margin-bottom: 10px;" icon="el-icon-share"
@click="handleClickLoad">引用接口自动化场景</el-button>
<el-table :data="changeList">
<el-table-column prop="name" label="场景名称" />
<el-table-column prop="status" label="Enable/Disable" />
<el-table-column prop="action" label="操作">
<template slot-scope="scope">
<el-button type="text" icon="el-icon-delete" style="color: red;"
@click="hadleClickDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="压力配置" name="second">
<div class="pressure-header">
<div class="title">速兑通接口</div>
<div class="pressure-title">并发用户数{{ addForm.concurrentThreads }}压测时长{{ addForm.pressureHour }}{{
addForm.pressureMinute }}{{ addForm.pressureSecond }}</div>
</div>
<div class="pressure-wrap">
<div class="pressure-warap-name">并发用户数</div>
<el-input-number v-model="addForm.concurrentThreads" controls-position="right" :min="0"></el-input-number>
</div>
<div class="pressure-wrap">
<div class="pressure-warap-name">取样器错误后</div>
<el-select v-model="addForm.errorOperType" placeholder="请选择">
<el-option key="1" label="继续" value="1"></el-option>
<el-option key="2" label="开始下一个线程轮询" value="2"></el-option>
<el-option key="3" label="停止线程" value="3"></el-option>
<el-option key="4" label="停止测试" value="4"></el-option>
<el-option key="5" label="立即停止测试" value="5"></el-option>
</el-select>
</div>
<div class="pressure-wrap">
<div class="pressure-warap-name">执行方式</div>
<el-radio-group v-model="addForm.executeType">
<el-radio-button :label="1">按持续时间</el-radio-button>
<el-radio-button :label="2">按迭代次数</el-radio-button>
</el-radio-group>
<el-input-number v-if="addForm.executeType === 2" style="margin-left: 10px;" v-model="addForm.loopCount"
controls-position="right" :min="0"></el-input-number>
</div>
<div class="pressure-wrap">
<div class="pressure-warap-name">Ramp-Up</div>
<el-input-number v-model="addForm.rampUpSeconds" controls-position="right" :min="0"></el-input-number>
<div class="pressure-warap-name"></div>
</div>
<div class="pressure-wrap">
<div class="pressure-warap-name">压测时长</div>
<el-input-number v-model="addForm.pressureHour" controls-position="right" :min="0"></el-input-number>
<div class="pressure-warap-name"></div>
<el-input-number v-model="addForm.pressureMinute" controls-position="right" :min="0"></el-input-number>
<div class="pressure-warap-name"></div>
<el-input-number v-model="addForm.pressureSecond" controls-position="right" :min="0"></el-input-number>
<div class="pressure-warap-name"></div>
</div>
<div class="pressure-wrap">
<div class="pressure-warap-name">Rps开启</div>
<el-switch v-model="addForm.rpsStatus" active-value="1" inactive-value="0"></el-switch>
<div class="pressure-warap-name">Rps上限</div>
<el-input-number v-model="addForm.rpsLimit" controls-position="right" :min="0"></el-input-number>
</div>
</el-tab-pane>
</el-tabs>
</div>
<el-dialog title="场景列表" :visible.sync="dialogVisible" width="60%">
<div class="search">
<el-input v-model="searchScenen.name" style="width: 300px;" placeholder="根据ID/名称/标签 搜索"
@blur="searchSecenList"></el-input>
</div>
<div class="table">
<el-table ref="tableRef" :data="sceneList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column prop="id" width="100" label="ID" align="center" />
<el-table-column prop="name" label="场景名称" align="center" />
<el-table-column prop="remark" label="标签" align="center" />
<el-table-column prop="createTime" label="修改时间" align="center" />
</el-table>
<div class="page">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange"
:page-size="searchScenen.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="totalScene" />
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="handleWithSure"> </el-button>
</span>
</el-dialog>
<el-dialog title="定时任务" :visible.sync="dialogVisibleTime" width="60%" :before-close="handleClose">
<el-tabs v-model="activeTime">
<el-tab-pane label="任务配置" name="first"></el-tab-pane>
<div class="editTimeTitle">编辑定时任务</div>
<div class="crontab-wrap">
<div class="title">Crontab表达式</div>
<el-input v-model="addForm.crontab" @input="updateExecutionTimes" placeholder="请输入crontab表达式" />
<div class="title" style="margin-left: 50px;">定时任务开关</div>
<el-switch v-model="addForm.crontabStatus" active-value="1" inactive-value="0"></el-switch>
</div>
<div class="near-time">
<div class="title">最近5次运行时间</div>
<div v-for="(item, index) in executionTimeList" :key="index">
{{ item.time }}
</div>
</div>
</el-tabs>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisibleTime = false, switchOpen = false"> </el-button>
<el-button type="primary" @click="dialogVisibleTime = false"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { editTest, editAndExecuteTest, getTestCaseList } from '../../../api/performance';
export default {
name: "PerformanceEdit",
data() {
return {
addForm: {
performanceName: '', // 性能测试名称
performanceTestCaseVOList: [], // 场景列表
concurrentThreads: '', // 并发用户数
errorOperType: '', // 在取样器错误后要执行的动作1继续2开始下一个线程轮询3停止线程4停止测试5立即停止测试
executeType: '', // 执行方式1按持续时间2按迭代次数
rampUpSeconds: '0', // 多少秒内线程建立完成默认0
pressureHour: '0', // 压测时长默认0
pressureMinute: '0', // 压测时长默认0
pressureSecond: '0', // 压测时长默认0
rpsStatus: '0', // rps状态0关闭1开启默认0
rpsLimit: '0', // 每分钟rps上限数默认0
crontab: '', // crontab表达式
crontabStatus: '0', // 定时任务状态0关闭1开启默认0
loopCount: '0', // 迭代次数默认0
},
activeName: 'first',
sceneList: [], // 场景列表
dialogVisible: false, // 场景列表
searchScenen: {
pageNum: 1,
pageSize: 10,
name: '', // 名称
},
totalScene: 0,
searchScene: '',
changeList: [],
multipleSelection: [],
switchOpen: false,
dialogVisibleTime: false,
activeTime: 'first',
executionTimeList: [
{
time: "2025-02-18 10:00:00",
},
{
time: "2025-02-19 10:00:00",
},
{
time: "2025-02-20 10:00:00",
},
{
time: "2025-02-21 10:00:00",
},
{
time: "2025-02-22 10:00:00",
},
],
}
},
mounted() {
this.getTestCaseData()
this.addForm = this.$route.query.data
},
methods: {
// 保存
handleWithSave() {
this.changeList.forEach(item => {
const par = {
testCaseId: item.id,
status: item.status
}
this.addForm.performanceTestCaseVOList.push(par)
})
editTest(this.addForm).then(res => {
if (res.code === 200) {
this.$message({ message: '编辑成功', type: 'success' })
this.$tab.closeOpenPage({ path: "/performance/performance" });
} else {
this.$message({ message: '编辑失败', type: 'error' })
}
})
},
// 保存并执行
handleWithSaveAndExecute() {
editAndExecuteTest(this.addForm).then(res => {
if (res.code === 200) {
this.$message({ message: '编辑成功', type: 'success' })
this.$tab.closeOpenPage({ path: "/performance/performance" });
} else {
this.$message({ message: '编辑失败', type: 'error' })
}
})
},
// 取消
handleWithCancel() {
this.$tab.closeOpenPage({ path: "/performance/performance" });
},
handleClick() { },
// 加载jmx文件
handleClickLoad() {
this.dialogVisible = true
},
// 删除
hadleClickDelete(val) {
this.changeList = this.changeList.filter(item => item !== val);
this.multipleSelection = this.multipleSelection.filter(item => item !== val);
this.sceneList.forEach(row => {
if (this.multipleSelection.includes(row)) {
this.$refs.tableRef.toggleRowSelection(row, true);
} else {
this.$refs.tableRef.toggleRowSelection(row, false);
}
})
},
// netWorking
getTestCaseData() {
getTestCaseList(this.searchScenen).then(res => {
if (res.code === 200) {
this.sceneList = res.rows
}
})
},
searchSecenList() {
this.getTestCaseData()
},
// 分页
handleSizeChange(val) {
this.searchScenen.pageSize = val
this.getTestCaseData()
},
handleCurrentChange(val) {
this.searchScenen.pageNum = val
this.getTestCaseData()
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
handleWithSure() {
this.changeList = this.multipleSelection
this.dialogVisible = false
},
switchChange(val) {
this.dialogVisibleTime = val
},
handleClose() {
this.dialogVisibleTime = false
this.switchOpen = false
},
// 根据crontab表达式更新执行时间
updateExecutionTimes() {
const crontab = this.form.crontab.trim();
if (!crontab) {
this.executionTimeList = [];
return;
}
try {
// 解析crontab表达式
const interval = cronParser.parseExpression(crontab);
const times = [];
// 获取最近三次执行时间
for (let i = 0; i < 3; i++) {
const nextTime = interval.next().toDate(); // 获取 Date 对象
const formattedTime = this.formatDate(nextTime); // 格式化时间
times.push({ time: formattedTime });
}
this.executionTimeList = times;
} catch (error) {
console.error('无效的crontab表达式:', error);
this.executionTimeList = [{ time: '无效的crontab表达式' }];
}
},
}
}
</script>
<style scoped lang="scss">
.performanceAdd {
padding: 20px;
.header {
display: flex;
justify-content: space-between;
.name {
display: flex;
width: 300px;
align-items: center;
.name-wrap {
width: 80px;
font-size: 14px;
}
}
}
.tab {
margin-top: 20px;
.title {
font-size: 14px;
font-weight: 600;
}
}
.search {
display: flex;
justify-content: flex-end;
margin-bottom: 10px;
}
.page {
padding: 10px;
display: flex;
justify-content: flex-end;
}
.pressure-header {
display: flex;
align-items: center;
margin-bottom: 10px;
.pressure-title {
margin-left: 20px;
font-size: 12px;
font-weight: 500;
}
}
.pressure-wrap {
display: flex;
padding: 10px;
align-items: center;
.pressure-warap-name {
font-size: 14px;
font-weight: 400;
margin: 0px 10px;
}
}
.date {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.date-top {
display: flex;
.date-title {
font-size: 14px;
font-weight: 500;
margin: 0px 10px;
}
}
.date-bottom {
display: flex;
margin: 10px;
}
}
.editTimeTitle {
font-size: 14px;
font-weight: 500;
margin-bottom: 10px;
}
.crontab-wrap {
display: flex;
align-items: center;
.title {
font-size: 14px;
width: 150px;
margin-right: 20px;
}
}
.near-time {
margin-top: 20px;
padding: 20px 10px;
border: solid #dcdfe6 1px;
}
}
</style>

View File

@@ -0,0 +1,9 @@
<script setup>
</script>
<template>
<p>报告</p>
</template>
<style scoped lang="scss"></style>

View File

@@ -35,7 +35,7 @@ module.exports = {
proxy: {
// detail: https://cli.vuejs.org/config/#devserver-proxy
[process.env.VUE_APP_BASE_API]: {
target: `http://localhost:8080`,
target: `http://ah.qyyh.net:1371/prod-api/`,
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''