add: 性能测试-报告
This commit is contained in:
@@ -69,3 +69,11 @@ export function editAndExecuteTest(data) {
|
|||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 测试-编辑-立即执行
|
||||||
|
export function executeTest(query) {
|
||||||
|
return request({
|
||||||
|
url: '/test/performanceTest/executeNow?' + query,
|
||||||
|
method: 'get',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -1 +1,26 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 报告-列表查询
|
||||||
|
export function getReportList(query) {
|
||||||
|
return request({
|
||||||
|
url: '/test/performanceReport//list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 报告-列表删除
|
||||||
|
export function deleteReport(data) {
|
||||||
|
return request({
|
||||||
|
url: '/test/performanceReport/delete/' + data,
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 报告-详情
|
||||||
|
export function getReportDetail(query) {
|
||||||
|
return request({
|
||||||
|
url: '/test/performanceReport/getInfo/' + query,
|
||||||
|
method: 'get',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ export default {
|
|||||||
addForm: {
|
addForm: {
|
||||||
performanceName: '', // 性能测试名称
|
performanceName: '', // 性能测试名称
|
||||||
performanceTestCaseVOList: [], // 场景列表
|
performanceTestCaseVOList: [], // 场景列表
|
||||||
concurrentThreads: '', // 并发用户数
|
concurrentThreads: '0', // 并发用户数
|
||||||
errorOperType: '', // 在取样器错误后要执行的动作,1:继续;2:开始下一个线程轮询;3:停止线程;4:停止测试;5:立即停止测试
|
errorOperType: '', // 在取样器错误后要执行的动作,1:继续;2:开始下一个线程轮询;3:停止线程;4:停止测试;5:立即停止测试
|
||||||
executeType: '', // 执行方式,1:按持续时间;2:按迭代次数
|
executeType: '', // 执行方式,1:按持续时间;2:按迭代次数
|
||||||
rampUpSeconds: '0', // 多少秒内线程建立完成,默认0
|
rampUpSeconds: '0', // 多少秒内线程建立完成,默认0
|
||||||
@@ -193,14 +193,36 @@ export default {
|
|||||||
time: "2025-02-22 10:00:00",
|
time: "2025-02-22 10:00:00",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
validation: false, // 校验
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.getTestCaseData()
|
this.getTestCaseData()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// 校验
|
||||||
|
validationForm() {
|
||||||
|
if (this.addForm.performanceName === '' || this.addForm.performanceName === null) {
|
||||||
|
this.$message({ message: '请输入测试名称', type: 'warning' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.addForm.errorOperType === '' || this.addForm.errorOperType === null) {
|
||||||
|
this.$message({ message: '请填写取样器错误后', type: 'warning' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.addForm.executeType === '' || this.addForm.executeType === null) {
|
||||||
|
this.$message({ message: '请选择执行方式', type: 'warning' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.validation = true
|
||||||
|
},
|
||||||
// 保存
|
// 保存
|
||||||
handleWithSave() {
|
handleWithSave() {
|
||||||
|
this.validationForm()
|
||||||
|
if (this.validation === false) { return }
|
||||||
this.changeList.forEach(item => {
|
this.changeList.forEach(item => {
|
||||||
var par = {
|
var par = {
|
||||||
testCaseId: item.id,
|
testCaseId: item.id,
|
||||||
@@ -208,7 +230,6 @@ export default {
|
|||||||
}
|
}
|
||||||
this.addForm.performanceTestCaseVOList.push(par)
|
this.addForm.performanceTestCaseVOList.push(par)
|
||||||
})
|
})
|
||||||
console.log(this.addForm)
|
|
||||||
addTest(this.addForm).then(res => {
|
addTest(this.addForm).then(res => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
this.$message({ message: '新增成功', type: 'success' })
|
this.$message({ message: '新增成功', type: 'success' })
|
||||||
@@ -220,6 +241,9 @@ export default {
|
|||||||
},
|
},
|
||||||
// 保存并执行
|
// 保存并执行
|
||||||
handleWithSaveAndExecute() {
|
handleWithSaveAndExecute() {
|
||||||
|
this.validationForm()
|
||||||
|
if (this.validation === false) { return }
|
||||||
|
// 需要校验crontab表达式
|
||||||
addAndExecuteTest(this.addForm).then(res => {
|
addAndExecuteTest(this.addForm).then(res => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
this.$message({ message: '新增成功', type: 'success' })
|
this.$message({ message: '新增成功', type: 'success' })
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
<div class="save">
|
<div class="save">
|
||||||
<el-button type="primary" plain @click="handleWithSave">保存</el-button>
|
<el-button type="primary" plain @click="handleWithSave">保存</el-button>
|
||||||
<el-button type="primary" plain @click="handleWithSaveAndExecute">保存并执行</el-button>
|
<el-button type="primary" plain @click="handleWithSaveAndExecute">保存并执行</el-button>
|
||||||
|
<el-button type="primary" plain @click="handleWithExecute">立即执行</el-button>
|
||||||
<el-button type="warning" plain @click="handleWithCancel">取消</el-button>
|
<el-button type="warning" plain @click="handleWithCancel">取消</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="date">
|
<div class="date">
|
||||||
@@ -143,7 +144,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { editTest, editAndExecuteTest, getTestCaseList, getTestDetail } from '../../../api/performance';
|
import { editTest, editAndExecuteTest, getTestCaseList, getTestDetail, executeTest } from '../../../api/performance';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "PerformanceEdit",
|
name: "PerformanceEdit",
|
||||||
@@ -233,6 +234,17 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
// 立即执行
|
||||||
|
handleWithExecute() {
|
||||||
|
executeTest(this.$route.query.id).then(res => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.$message({ message: '执行成功', type: 'success' })
|
||||||
|
this.$tab.closeOpenPage({ path: "/performance/performance" });
|
||||||
|
} else {
|
||||||
|
this.$message({ message: '执行失败', type: 'error' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
// 取消
|
// 取消
|
||||||
handleWithCancel() {
|
handleWithCancel() {
|
||||||
this.$tab.closeOpenPage({ path: "/performance/performance" });
|
this.$tab.closeOpenPage({ path: "/performance/performance" });
|
||||||
|
|||||||
@@ -9,16 +9,24 @@
|
|||||||
<div class="table">
|
<div class="table">
|
||||||
<el-table :data="data">
|
<el-table :data="data">
|
||||||
<el-table-column type="selection" width="55" />
|
<el-table-column type="selection" width="55" />
|
||||||
<el-table-column prop="name0" label="名称" align="center" sortable />
|
<el-table-column prop="name" label="名称" align="center" sortable width="150" />
|
||||||
<el-table-column prop="name1" label="创建人" align="center" width="150" sortable />
|
<el-table-column prop="createBy" label="创建人" align="center" width="150" sortable />
|
||||||
<el-table-column prop="name2" label="并发数" align="center" width="150" sortable />
|
<el-table-column prop="concurrentThreads" label="并发数" align="center" width="150" sortable />
|
||||||
<el-table-column prop="name3" label="响应(s)" align="center" width="150" sortable />
|
<el-table-column prop="tps" label="TPS" align="center" width="150" sortable />
|
||||||
<el-table-column prop="name4" label="TPS" align="center" width="150" sortable />
|
<el-table-column prop="startTime" label="开始时间" align="center" sortable />
|
||||||
<el-table-column prop="name5" label="开始时间" align="center" width="150" sortable />
|
<el-table-column prop="endTime" label="结束时间" align="center" sortable />
|
||||||
<el-table-column prop="name6" label="结束时间" align="center" width="150" sortable />
|
<el-table-column prop="triggerType" label="触发方式" align="center" sortable>
|
||||||
<el-table-column prop="name7" label="执行时长" align="center" width="150" sortable />
|
<template slot-scope="scope">
|
||||||
<el-table-column prop="name8" label="触发方式" align="center" width="150" sortable />
|
<div v-if="scope.row.triggerType === 1">按持续时间</div>
|
||||||
<el-table-column prop="name9" label="状态" align="center" width="150" sortable />
|
<div v-else>按迭代次数</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="status" label="状态" align="center" width="150" sortable>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<div v-if="scope.row.triggerType === 1">开启</div>
|
||||||
|
<div v-else>关闭</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="action" label="操作" align="center" width="150" fixed="right">
|
<el-table-column prop="action" label="操作" align="center" width="150" fixed="right">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button type="text" icon="el-icon-view" @click="hadleClickDetail(scope.row)">查看</el-button>
|
<el-button type="text" icon="el-icon-view" @click="hadleClickDetail(scope.row)">查看</el-button>
|
||||||
@@ -36,6 +44,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { getReportList, deleteReport } from '../../../api/performance/report';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Report",
|
name: "Report",
|
||||||
data() {
|
data() {
|
||||||
@@ -46,24 +56,41 @@ export default {
|
|||||||
performanceName: '', // 名称
|
performanceName: '', // 名称
|
||||||
},
|
},
|
||||||
total: 0,
|
total: 0,
|
||||||
data: [{}, {}],
|
data: [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.getReportListData()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 查看
|
// 查看
|
||||||
hadleClickDetail() {
|
hadleClickDetail(val) {
|
||||||
this.$tab.openPage("报告详情", "/performance/report/detail");
|
this.$tab.openPage("报告详情", "/performance/report/detail", { id: val.id });
|
||||||
},
|
},
|
||||||
// 删除’
|
// 删除
|
||||||
hadleClickDelete() {
|
hadleClickDelete(val) {
|
||||||
|
deleteReport(val.id).then(res => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.$message({ message: '删除成功', type: 'success' })
|
||||||
|
this.getReportListData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 获取列表数据
|
||||||
|
getReportListData() {
|
||||||
|
getReportList(this.serachForm).then(res => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.data = res.rows
|
||||||
|
this.total = res.total
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
// 分页
|
// 分页
|
||||||
handleSizeChange() { },
|
handleSizeChange() { },
|
||||||
handleCurrentChange() { },
|
handleCurrentChange() { },
|
||||||
serachList() { },
|
serachList() {
|
||||||
|
this.getReportListData()
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,63 +1,85 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="report-detail">
|
<div class="report-detail">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="title">执行时长</div>
|
<div class="title">执行时长:{{ detailData ? detailData.costTime : '' }}</div>
|
||||||
<div class="title">开始时间</div>
|
<div class="title">开始时间:{{ detailData ? detailData.startTime : '' }}</div>
|
||||||
<div class="title">结束时间</div>
|
<div class="title">结束时间:{{ detailData ? detailData.endTime : ' ' }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
<el-tabs v-model="activeName">
|
<el-tabs v-model="activeName">
|
||||||
<el-tab-pane label="请求统计" name="first">
|
<el-tab-pane label="请求统计" name="first">
|
||||||
<div class="btn-wrap">
|
|
||||||
<el-button @click="exportExcel">导出为Excel</el-button>
|
|
||||||
</div>
|
|
||||||
<el-table :data="statisticsData">
|
<el-table :data="statisticsData">
|
||||||
<el-table-column label="Requests" align="center">
|
<el-table-column label="Requests" align="center">
|
||||||
<el-table-column prop="name" label="Label" width="120" sortable align="center" />
|
<el-table-column prop="label" label="Label" sortable align="center" />
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="Executions" align="center">
|
<el-table-column label="Executions" align="center">
|
||||||
<el-table-column prop="name" label="Samples" width="120" sortable align="center" />
|
<el-table-column prop="samples" label="Samples" sortable align="center" />
|
||||||
<el-table-column prop="name" label="FAIL" width="120" sortable align="center" />
|
|
||||||
<el-table-column prop="name" label="Error%" width="120" sortable align="center" />
|
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="Response Times(ms)" align="center">
|
<el-table-column label="Response Times(ms)" align="center">
|
||||||
<el-table-column prop="name" label="Avg" width="120" sortable align="center" />
|
<el-table-column prop="average" label="Avg" sortable align="center" />
|
||||||
<el-table-column prop="name" label="Min" width="120" sortable align="center" />
|
<el-table-column prop="min" label="Min" sortable align="center" />
|
||||||
<el-table-column prop="name" label="Max" width="120" sortable align="center" />
|
<el-table-column prop="max" label="Max" sortable align="center" />
|
||||||
<el-table-column prop="name" label="Med" width="120" sortable align="center" />
|
<el-table-column prop="errorRate" label="ErrorRate" sortable align="center">
|
||||||
<el-table-column prop="name" label="90%" width="120" sortable align="center" />
|
<template slot-scope="scope">
|
||||||
<el-table-column prop="name" label="95%" width="120" sortable align="center" />
|
<div>{{ getFormatToTwoDecimalPlaces(scope.row.errorRate) }}%</div>
|
||||||
<el-table-column prop="name" label="99%" width="120" sortable align="center" />
|
</template>
|
||||||
|
</el-table-column>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="Throughput" align="center">
|
<el-table-column label="Throughput" align="center">
|
||||||
<el-table-column prop="name" label="Trans/s" width="120" sortable align="center" />
|
<el-table-column prop="throughput" label="Trans/s" width="120" sortable align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<div>{{ getFormatToTwoDecimalPlaces(scope.row.throughput) }}%</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="NetWork(KB/Sec)" align="center">
|
<el-table-column label="NetWork(KB/Sec)" align="center">
|
||||||
<el-table-column prop="name" label="Recd" width="120" sortable align="center" />
|
<el-table-column prop="receivedKBPerSec" label="Recd" width="120" sortable align="center">
|
||||||
<el-table-column prop="name" label="Sent" width="120" sortable align="center" />
|
<template slot-scope="scope">
|
||||||
|
<div>{{ getFormatToTwoDecimalPlaces(scope.row.receivedKBPerSec) }}%</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="sentKBPerSec" label="Sent" width="120" sortable align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<div>{{ getFormatToTwoDecimalPlaces(scope.row.sentKBPerSec) }}%</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="错误记录" name="second">
|
<el-tab-pane label="错误记录" name="second">
|
||||||
<div class="title-error">Errors</div>
|
<div class="title-error">Errors</div>
|
||||||
<el-table :data="errorList" border>
|
<el-table :data="errorCodeStatList" border>
|
||||||
<el-table-column prop="date" label="Type of error" sortable />
|
<el-table-column prop="responseCode" label="Type of error" sortable align="center" />
|
||||||
<el-table-column prop="name" label="Number of errors" sortable />
|
<el-table-column prop="count" label="Number of errors" sortable align="center" />
|
||||||
<el-table-column prop="address" label="% in errors" sortable />
|
<el-table-column prop="errorRatio" label="% in errors" sortable align="center">
|
||||||
<el-table-column prop="address" label="% in samples" sortable />
|
<template slot-scope="scope">
|
||||||
|
<div>{{ getFormatToTwoDecimalPlaces(scope.row.errorRatio) }}%</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="totalRatio" label="% in samples" sortable align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<div>{{ getFormatToTwoDecimalPlaces(scope.row.totalRatio) }}%</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<div class="title-error">Top 5 Errors</div>
|
<div class="title-error">Top 5 Errors</div>
|
||||||
<el-table :data="errorList" border>
|
<el-table :data="top5InterfaceErrorStatList" border>
|
||||||
<el-table-column prop="date" label="Sample" sortable />
|
<el-table-column prop="interfaceName" label="Sample" sortable align="center" />
|
||||||
<el-table-column prop="name" label="#Samples" sortable />
|
<el-table-column prop="errorCount" label="#Samples" sortable align="center" />
|
||||||
<el-table-column prop="address" label="All Errors" sortable />
|
<el-table-column prop="totalSamples" label="All Errors" sortable align="center" />
|
||||||
</el-table>
|
</el-table>
|
||||||
<div class="title-error">#1 Errors</div>
|
<div v-for="(item, index) in interfaceErrorDetailList">
|
||||||
<el-table :data="errorList" border>
|
<div class="title-error">#{{ index + 1 }} Errors</div>
|
||||||
<el-table-column prop="date" label="Sample" sortable />
|
<el-table :data="interfaceErrorDetailList" border>
|
||||||
<el-table-column prop="name" label="#1 Error" sortable />
|
<el-table-column prop="interfaceName" label="Sample" sortable align="center" />
|
||||||
<el-table-column prop="address" label="#1 Error Count" sortable />
|
<el-table-column prop="errorName" :label="getLabel(index)" sortable align="center">
|
||||||
|
<template slot-scope="scope">{{ getErrorName(scope.row) }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="errorCount" :label="getErrorCount(index)" sortable align="center">
|
||||||
|
<template slot-scope="scope">{{ getErrorCountDetail(scope.row) }}</template>
|
||||||
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
@@ -65,21 +87,62 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { getReportDetail } from '../../../api/performance/report';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "ReportDetail",
|
name: "ReportDetail",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
activeName: 'first',
|
activeName: 'first',
|
||||||
statisticsData: [], // 统计
|
statisticsData: [], // 统计
|
||||||
errorList: []
|
errorCodeStatList: [],
|
||||||
|
top5InterfaceErrorStatList: [],
|
||||||
|
interfaceErrorDetailList: [],
|
||||||
|
detailData: null,
|
||||||
|
errorReport: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.getReportDetailData()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 导出excel
|
getReportDetailData() {
|
||||||
exportExcel() {
|
getReportDetail(this.$route.query.id).then(res => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.detailData = res.data
|
||||||
|
this.statisticsData = JSON.parse(res.data.summaryReport)
|
||||||
|
this.errorReport = JSON.parse(res.data.errorReport)
|
||||||
|
this.errorCodeStatList = this.errorReport.errorCodeStatList
|
||||||
|
this.top5InterfaceErrorStatList = this.errorReport.top5InterfaceErrorStatList
|
||||||
|
this.interfaceErrorDetailList = this.errorReport.interfaceErrorDetailList
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 保留2为小数
|
||||||
|
getFormatToTwoDecimalPlaces(num) {
|
||||||
|
return Math.round(num * 100) / 100;
|
||||||
|
},
|
||||||
|
getLabel(index) {
|
||||||
|
const i = index + 1
|
||||||
|
return '#' + i + ' Error'
|
||||||
|
},
|
||||||
|
getErrorCount(index) {
|
||||||
|
const i = index + 1
|
||||||
|
return '#' + i + ' Error ' + 'Count'
|
||||||
|
},
|
||||||
|
getErrorName(val) {
|
||||||
|
var key1 = ''
|
||||||
|
for (let key in val.errorCodeCounts) {
|
||||||
|
key1 = key
|
||||||
|
}
|
||||||
|
return key1
|
||||||
|
},
|
||||||
|
getErrorCountDetail(val) {
|
||||||
|
var keyV = ''
|
||||||
|
for (let key in val.errorCodeCounts) {
|
||||||
|
keyV = val.errorCodeCounts[key]
|
||||||
|
}
|
||||||
|
return keyV
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,11 +169,6 @@ export default {
|
|||||||
.tabs {
|
.tabs {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
|
||||||
.btn-wrap {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.title-error {
|
.title-error {
|
||||||
|
|||||||
Reference in New Issue
Block a user