micro-ui/src/views/quality/checkjob/CheckJobDetail.vue
2024-01-03 15:08:03 +08:00

380 lines
19 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-card class="box-card" shadow="always">
<div slot="header" class="clearfix">
<span>{{ title }}</span>
<el-button-group style="float: right;">
<el-button size="mini" type="primary" @click="executionSchedule">执行</el-button>
<el-button size="mini" icon="el-icon-back" @click="showCard">返回</el-button>
</el-button-group>
</div>
<div class="body-wrapper">
<el-descriptions title="检测场景" :column="2" border size="medium" >
<el-descriptions-item :labelStyle="{width: '200px'}">
<template slot="label">
检测场景
</template>
<div class="app-pts-web-card style-module__grid-item--2nHmp" style="height: 200px; width:40%;margin: 10px;">
<div class="app-pts-web-card__body">
<div class="app-pts-web-card__title">
<div class="app-pts-web-justify-grid">
<div class="app-pts-web-justify-grid__col app-pts-web-justify-grid__col--left">
<h3 class="app-pts-web-h3"><span class="" style="color: rgb(0, 0, 0);">简单模式</span></h3>
</div>
</div>
</div>
<div class="app-pts-web-card__content">
<div class="app-pts-web-justify-grid">
<div class="app-pts-web-justify-grid__col app-pts-web-justify-grid__col--left">
<p class="" style="min-height: 50px; font-size: 12px; line-height: 20px;">使用我们的交互式 UI 组合接入数据源定义数据模型创建检测用例执行检测任务查看检测结果与报告生成</p>
</div>
<div class="app-pts-web-justify-grid__col app-pts-web-justify-grid__col--right">
<img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIwIiBoZWlnaHQ9IjEyMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGRlZnM+PHBhdGggaWQ9ImEiIGQ9Ik0wIDBoMjMuMzk5djEzLjUxN0gweiIvPjxwYXRoIGlkPSJjIiBkPSJNMCAwaDEwLjYydjYuMTQ1SDB6Ii8+PC9kZWZzPjxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+PHBhdGggZmlsbD0iI0VCRjRGRiIgZD0iTTkyLjQ2MyAzNy4zNTFsLTIwLjk4LTEyLjExMy0xNi42NzcgOS42OTEgMjAuOTggMTIuMTEyek01Ny44OTcgOTMuNDQ0bDI3LjMyIDE1LjkyMyAzMC4yODYtMTcuNzk3LTI3LjMxOC0xNS45MjN6Ii8+PHBhdGggZmlsbD0iI0E3Q0RGRiIgZD0iTTY2LjgyMiA1My4xNzdMMzYuNTM0IDcwLjk3NGw0OC42NDggMjguMzk4IDMwLjI4Ny0xNy43OTZ6Ii8+PHBhdGggZmlsbD0iIzAwNkVGRiIgZD0iTTY2LjgyMiA1My4xNzdsNDguNjQ3IDI4LjQtNC4yNTcgMi41TDYyLjU3OSA1NS42N3oiLz48cGF0aCBkPSJNNjEuODU0IDcwLjgxOWwyOS43ODIgMTcuNDA0IDkuNzQxLTUuNzNMNzEuNTk0IDY1LjA5bC05Ljc0IDUuNzN6bS00LjMwNiAyLjUzM0w4Ny4zMyA5MC43NTZsMi4xNDQtMS4yNjFMNTkuNjkgNzIuMDlsLTIuMTQyIDEuMjZ6bS00LjMwNyAyLjUzMmwyOS43ODMgMTcuNDA0IDIuMTQ0LTEuMjYtMjkuNzgyLTE3LjQwNi0yLjE0NSAxLjI2MnoiIGZpbGw9IiNFQkY0RkYiLz48cGF0aCBkPSJNNjcuNDAzIDU1Ljc3N2MtLjMyOS4xOTMtLjMyOS41MDYuMDAzLjcuMzMxLjE5My44NjguMTkzIDEuMTk3IDAgLjMyOC0uMTk0LjMyNS0uNTA3LS4wMDYtLjdhMS4yMDYgMS4yMDYgMCAwMC0uNTk4LS4xNDVjLS4yMTYgMC0uNDMxLjA0OC0uNTk2LjE0NXptMi40NjYgMS40MzljLS4zMjkuMTkzLS4zMjkuNTA2LjAwMy43LjMzMS4xOTMuODY4LjE5MyAxLjE5NiAwIC4zMjktLjE5NC4zMjYtLjUwNy0uMDA1LS43YTEuMjA3IDEuMjA3IDAgMDAtLjU5OC0uMTQ2Yy0uMjE2IDAtLjQzMS4wNDktLjU5Ni4xNDZ6bTIuNDY2IDEuNDRjLS4zMjkuMTkyLS4zMjkuNTA2LjAwMy43LjMzMS4xOTIuODY4LjE5MiAxLjE5NiAwIC4zMjktLjE5NC4zMjYtLjUwOC0uMDA1LS43YTEuMjA2IDEuMjA2IDAgMDAtLjU5OC0uMTQ1Yy0uMjE2IDAtLjQzMi4wNDgtLjU5Ni4xNDV6IiBmaWxsPSIjRkZGIi8+PHBhdGggc3Ryb2tlPSIjMDA2RUZGIiBkPSJNNjguNjY4IDM5LjU5TDM4IDU3LjUyNyA4Ny4yNTkgODYuMTVsMzAuNjY3LTE3LjkzN3pNNjQuMjM3IDQyLjE4MWw0OS4wMDEgMjguNTQ2Ii8+PHBhdGggZmlsbD0iI0VCRjRGRiIgZD0iTTAgNTAuNTcyTDI3Ljk0OSA2Ni41IDQ1LjM1IDU2LjUyIDE3LjQwMSA0MC41OXoiLz48cGF0aCBmaWxsPSIjQTdDREZGIiBkPSJNMTcuNDM1IDQwLjU5bDI3Ljk1IDE1LjkzLTIuNTQ5IDEuNDYtMjcuOTUtMTUuOTI3eiIvPjxwYXRoIGQ9Ik0yNS42NTkgNTEuMzc3YzEuOTQ2IDEuMTA1IDEuOTU0IDIuODkxLjAyMSAzLjk5NS0uODIyLjQ3LTEuODUyLjczLTIuOTAzLjgxMWwuMDExIDEuNTUxSDIxLjU5bC0uMDA5LTEuNTVjLTEuMDUxLS4wODQtMi4wODYtLjM0LTIuOTE0LS44MTItMS45NDYtMS4xMDQtMS45NTYtMi44ODktLjAyNC0zLjk5NCAxLjkzMy0xLjEwNCA1LjA3MS0xLjEwNSA3LjAxNiAwem0tNi4xOTQuNDczYy0xLjQ4Mi44NjEtMS40NzUgMi4yNTIuMDE4IDMuMTE0IDEuNDkzLjg2MiAzLjg5NC44NjIgNS4zNzYgMCAxLjQ4My0uODYyIDEuNDc1LTIuMjUyLS4wMTktMy4xMTQtMS40OTMtLjg2NC0zLjg5MS0uODY0LTUuMzc1IDB6IiBmaWxsPSIjMDA2RUZGIi8+PHBhdGggZmlsbD0iI0VCRjRGRiIgZD0iTTc0LjA3NiAxNy4zMjdsLTMuNTIxIDIuMDQ2LTcuMDkzLTQuMDk2IDMuNTItMi4wNDZ6Ii8+PHBhdGggZmlsbD0iI0E3Q0RGRiIgZD0iTTYyLjc1NyAxNS42ODZsLjcwNC0uNDA5IDcuMDk0IDQuMDk2LS43MDQuNDF6Ii8+PHBhdGggZmlsbD0iI0VCRjRGRiIgZD0iTTY5Ljg1MSAxOS43ODJsLTMuNTI3IDIuMDUtNy4wOTMtNC4wOTYgMy41MjYtMi4wNXoiLz48cGF0aCBmaWxsPSIjQTdDREZGIiBkPSJNNTguNTI3IDE4LjE0NWwuNzA0LS40MDkgNy4wOTMgNC4wOTYtLjcwNC40MXoiLz48cGF0aCBmaWxsPSIjRUJGNEZGIiBkPSJNODAuNDYgMjEuMDEzbC0zLjUyIDIuMDQ2LTUuNjc2LTMuMjc2IDMuNTItMi4wNDZ6Ii8+PHBhdGggZmlsbD0iI0E3Q0RGRiIgZD0iTTcwLjU2IDIwLjE5MWwuNzA0LS40MDkgNS42NzYgMy4yNzYtLjcwNC40MXoiLz48cGF0aCBmaWxsPSIjQTdDREZGIiBkPSJNNzQuNzg1IDE3LjczNmwtMy41MjEgMi4wNDYtLjcwNC40MS0zLjUyNyAyLjA1LS43MDQuNDA4LTMuNTI2IDIuMDUtLjcxLS40MSAzLjUyOC0yLjA0OS43MDQtLjQwOSAzLjUyNi0yLjA1LjcwNS0uNDA5IDMuNTItMi4wNDZ6Ii8+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNjYuOTgyIDEyKSI+PG1hc2sgaWQ9ImIiIGZpbGw9IiNmZmYiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48L21hc2s+PHBhdGggZmlsbD0iI0E3Q0RGRiIgbWFzaz0idXJsKCNiKSIgZD0iTTIzLjM5OSAxMi4yODZsLTIuMTE5IDEuMjMxLTcuMDk0LTQuMDk1LS43MDgtLjQwOS01LjY3Ni0zLjI3Ny0uNzA5LS40MDlMMCAxLjIzMSAyLjExOSAweiIvPjwvZz48cGF0aCBmaWxsPSIjRUJGNEZGIiBkPSJNNzYuMjM2IDIzLjQ2OGwtMy41MjcgMi4wNS01LjY3Ni0zLjI3NyAzLjUyNy0yLjA1eiIvPjxwYXRoIGZpbGw9IiNBN0NERkYiIGQ9Ik02Ni4zMjkgMjIuNjVsLjcwNC0uNDA5IDUuNjc2IDMuMjc2LS43MDQuNDF6TTc3LjY0OSAyMy40NjhsNy4wOTMgNC4wOTYtLjcwNC40MDktNy4wOTMtNC4wOTZ6Ii8+PHBhdGggZmlsbD0iI0VCRjRGRiIgZD0iTTY2LjMyOSAyMi42NWw1LjY3NiAzLjI3Ni0zLjUyNyAyLjA1LTUuNjc1LTMuMjc3eiIvPjxwYXRoIGZpbGw9IiNBN0NERkYiIGQ9Ik04MS4xNjggMjEuNDIybC0zLjUyIDIuMDQ2LS43MDMuNDA5LTMuNTI3IDIuMDUtLjcwNS40MDktMy41MjUgMi4wNS0uNzEtLjQxIDMuNTI3LTIuMDUuNzA0LS40MDggMy41MjYtMi4wNS43MDUtLjQxIDMuNTItMi4wNDV6Ii8+PHBhdGggZmlsbD0iI0VCRjRGRiIgZD0iTTczLjQxNyAyNS45MjdsMy41MjctMi4wNSA3LjA5MyA0LjA5Ni0zLjUyNiAyLjA1eiIvPjxwYXRoIGZpbGw9IiNBN0NERkYiIGQ9Ik03My40MTcgMjUuOTI3bDcuMDk0IDQuMDk2LS43MDQuNDA5LTcuMDk0LTQuMDk2eiIvPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDY5LjE4NyAyNi4zMzYpIj48bWFzayBpZD0iZCIgZmlsbD0iI2ZmZiI+PHVzZSB4bGluazpocmVmPSIjYyIvPjwvbWFzaz48cGF0aCBmaWxsPSIjRUJGNEZGIiBtYXNrPSJ1cmwoI2QpIiBkPSJNMCAyLjA1TDMuNTI2IDBsNy4wOTQgNC4wOTYtMy41MjcgMi4wNXoiLz48L2c+PHBhdGggZmlsbD0iI0VCRjRGRiIgZD0iTTgxLjE2OCAyMS40MjJsNy4wOTQgNC4wOTYtMy41MiAyLjA0Ni03LjA5NC00LjA5NnpNNTUgMjAuMTk0di4wMDFsNy4wOTMgNC4wOTUgMy41MjctMi4wNS03LjA5My00LjA5NXoiLz48cGF0aCBkPSJNNzkuODk2IDI5LjVjLTIuMzE4LTEuMzM3LTYuMDYtMS4zMzctOC4zNjIgMC0uMzYuMjEtLjY2Mi40MzgtLjkwOS42ODItMS4zMzQgMS4zMTMtMS4wMiAzLjAzNC45MzYgNC4xNjMgMi4zMTcgMS4zMzggNi4wNiAxLjMzOCA4LjM2MSAwIDEuOTQ0LTEuMTMgMi4yNC0yLjg1Ljg5LTQuMTYzYTQuMTA3IDQuMTA3IDAgMDAtLjQ2Mi0uMzg3IDUuNjQxIDUuNjQxIDAgMDAtLjQ1NC0uMjk0bS02Ljc4OCAxLjUxMmwxLjA0LS42MDUgMS41NzcuOTEgMS41NjctLjkxIDEuMDQ2LjYwNS0xLjU2Ni45MSAxLjU3Ny45MS0xLjA0LjYwNi0xLjU3Ny0uOTEyLTEuNTY3LjkxMi0xLjA0Ny0uNjA1IDEuNTY2LS45MTEtMS41NzYtLjkxIiBmaWxsPSIjMDA2RUZGIi8+PHBhdGggZmlsbD0iI0ZGRiIgZD0iTTc4LjMzOCAzMS4wMTJsLTEuMDQ2LS42MDQtMS41NjcuOTEtMS41NzYtLjkxLTEuMDQuNjA0IDEuNTc2LjkxLTEuNTY3LjkxMSAxLjA0Ny42MDUgMS41NjctLjkxIDEuNTc2LjkxIDEuMDQxLS42MDUtMS41NzctLjkxeiIvPjwvZz48L3N2Zz4=" style="width: 120px;">
</div>
</div>
</div>
</div>
</div>
</el-descriptions-item>
</el-descriptions >
<el-descriptions style="margin-top: 20px" title="任务信息" :column="2" :colon="false" border size="medium">
<el-descriptions-item :labelStyle="{width: '200px'}" :contentStyle="{width: '35%'}">
<template slot="label">
任务名称
</template>
{{form.jobName}}
</el-descriptions-item>
<el-descriptions-item :labelStyle="{width: '200px'}">
<template slot="label">
任务类型
</template>
<template v-for="item in ruleItemOptions">
<span v-if="form.jobType == item.typeId" size="small" type="success">{{ item.typeName }}</span>
</template>
</el-descriptions-item>
<el-descriptions-item :labelStyle="{width: '200px'}" :contentStyle="{width: '35%'}">
<template slot="label">
cron表达式
</template>
{{form.cronExpression}}
</el-descriptions-item>
<el-descriptions-item :labelStyle="{width: '200px'}">
<template slot="label">
定时状态
</template>
<template v-for="dict in statusOptions">
<el-tag v-if="form.status == dict.itemText && form.status == '1' " size="small" type="success">{{ selectDictLabel(statusOptions, form.status) }}</el-tag>
<el-tag v-if="form.status == dict.itemText && form.status != '1' " size="small" type="warning">{{ selectDictLabel(statusOptions, form.status) }}</el-tag>
</template>
</el-descriptions-item>
<el-descriptions-item :labelStyle="{width: '200px'}">
<template slot="label">
任务概述
</template>
{{form.remark}}
</el-descriptions-item>
</el-descriptions>
<el-descriptions style="margin-top: 20px" title="检测用例" :column="2" border size="medium" >
<el-descriptions-item :labelStyle="{width: '200px'}">
<template slot="label">
检测用例
</template>
<template v-for="item in checkCaseOptions">
<el-tag effect="plain" :key="item.id" style="margin-left: 20px">{{ item.ruleName }}</el-tag>
</template>
</el-descriptions-item>
</el-descriptions >
<el-descriptions style="margin-top: 20px" title="检测进度" :column="2" border size="medium" >
<el-descriptions-item :labelStyle="{width: '200px'}">
<template slot="label">
检测进度
</template>
<div style="height: 300px;">
<el-steps direction="vertical" v-if="scheduleOptions.showScheduleSteps" :active="scheduleOptions.scheduleActive">
<el-step title="连接数据源">
<template slot="description">
<div v-if="scheduleOptions.showScheduleDataSourceDesc1">正在连接数据源数据平台......</div>
<div v-if="scheduleOptions.showScheduleDataSourceDesc2">数据源连接成功</div>
</template>
</el-step>
<el-step title="检测执行初始化">
<template slot="description">
<div v-if="scheduleOptions.showScheduleInitDesc1">开始进行检测执行初始化......</div>
<div v-if="scheduleOptions.showScheduleInitDesc2">检测执行前初始化成功</div>
</template>
</el-step>
<el-step title="开始执行检测">
<template slot="description">
<div v-if="scheduleOptions.showScheduleResulteDesc1">开始执行检测......</div>
<div v-if="scheduleOptions.showScheduleResulteDesc2"><el-progress :percentage="scheduleOptions.percentage"></el-progress></div>
<div v-if="scheduleOptions.showScheduleResulteDesc3">检测执行成功可在检测结果管理查看检测结果报告</div>
</template>
</el-step>
</el-steps>
</div>
</el-descriptions-item>
</el-descriptions >
</div>
</el-card>
</template>
<script>
import { updateCheckJob, getScheduleJobById } from '@/api/quality/checkjob'
import { pageCheckRule } from '@/api/quality/checkrule'
export default {
name: 'CheckJobDetail',
props: {
data: {
type: Object,
default: function () {
return {}
}
}
},
data() {
return {
title: '检测任务详情',
// 展示切换
showOptions: {
data: {},
showList: true,
showAdd: false,
showEdit: false,
showDetail: false
},
scheduleOptions:{
showScheduleDataSourceDesc1: false,
showScheduleDataSourceDesc2: false,
showScheduleInitDesc1: false,
showScheduleInitDesc2: false,
showScheduleResulteDesc1: false,
showScheduleResulteDesc2: false,
showScheduleResulteDesc3: false,
showScheduleSteps: false,
scheduleActive: 0,
percentage: 0
},
scheduleOptionsArr: [
{id:'showScheduleDataSourceDesc1', time: 1000},
{id:'showScheduleDataSourceDesc2', time: 2000},
{id:'showScheduleInitDesc1', time: 3000},
{id:'showScheduleInitDesc2', time: 4000},
{id:'showScheduleResulteDesc1', time: 5000},
{id:'showScheduleResulteDesc2', time: 6000}
],
// 保存按钮
loadingOptions: {
loading: false,
loadingText: '保存',
isDisabled: false
},
// 表单参数
form: {},
// 表单校验
rules: {
jobName: [
{ required: true, message: '任务名称不能为空', trigger: 'blur' }
],
jobType: [
{ required: true, message: '任务类型不能为空', trigger: 'change' }
],
cronExpression: [
{ required: true, message: 'cron表达式不能为空', trigger: 'blur' }
]
},
// 状态数据字典
statusOptions: [],
// 规则级别数据字典
ruleLevelOptions: [],
// 核查类型数据字典
ruleItemOptions: [
{ typeId: 'structure', typeName: '结构符合性' },
{ typeId: 'content', typeName: '内容符合性' },
{ typeId: 'relevance', typeName: '关联符合性' }
],
checkCaseOptions: [],
sourceOptions: [],
tableOptions: [],
columnOptions: [],
dictTypeOptions: [],
relatedColumnOptions: []
}
},
created() {
this.form.jobType = this.data.jobType
this.getDicts('sys_job_status').then(response => {
if (response.success) {
this.statusOptions = response.data
}
})
this.getCheckRule()
},
mounted() {
this.getCheckJob(this.data.id)
},
methods: {
/** 获取详情 */
async getCheckJob(id) {
this.form = await getScheduleJobById(id).then(response => {
if (response.success) {
console.log('response==', response)
return response.data
}
})
},
showCard() {
this.$emit('showCard', this.showOptions)
},
ruleItemSelectChanged(val) {
const item = this.ruleItemOptions.find(function (item) {
return item.typeId === val
})
this.form.jobType = item.typeId
},
getCheckRule() {
let ruleType = 'nr'
if(this.form.jobType == 'structure'){
ruleType = 'jg'
} else if(this.form.jobType == 'relevance'){
ruleType = 'gl'
}
let params = {
pageNum: 1,
pageSize: 20,
projectId: '1111',
ruleTypeId: '',
ruleName: '',
ruleType: ruleType
}
this.checkCaseOptions = []
pageCheckRule(params).then(response => {
if (response.success) {
const { data } = response
this.checkCaseOptions = data.data
}
})
},
/** 提交按钮 */
submitForm: function () {
this.$refs['form'].validate(valid => {
if (valid) {
this.loadingOptions.loading = true
this.loadingOptions.loadingText = '保存中...'
this.loadingOptions.isDisabled = true
updateCheckJob(this.form).then(response => {
if (response.success) {
this.$message.success('保存成功')
setTimeout(() => {
// 2秒后跳转列表页
this.$emit('showCard', this.showOptions)
}, 2000)
} else {
this.$message.error('保存失败')
this.loadingOptions.loading = false
this.loadingOptions.loadingText = '保存'
this.loadingOptions.isDisabled = false
}
}).catch(() => {
this.loadingOptions.loading = false
this.loadingOptions.loadingText = '保存'
this.loadingOptions.isDisabled = false
})
}
})
},
executionSchedule(){
this.scheduleOptions.showScheduleSteps = true
for(let i=0; i<this.scheduleOptionsArr.length; i++){
if(this.scheduleOptionsArr[i].id == 'showScheduleDataSourceDesc1'){
setTimeout(() => {
this.scheduleOptions.showScheduleDataSourceDesc1 = true
}, this.scheduleOptionsArr[i].time)
} else if(this.scheduleOptionsArr[i].id == 'showScheduleDataSourceDesc2'){
setTimeout(() => {
this.scheduleOptions.showScheduleDataSourceDesc2 = true
this.scheduleOptions.scheduleActive = 1
}, this.scheduleOptionsArr[i].time)
} else if(this.scheduleOptionsArr[i].id == 'showScheduleInitDesc1'){
setTimeout(() => {
this.scheduleOptions.showScheduleInitDesc1 = true
}, this.scheduleOptionsArr[i].time)
} else if(this.scheduleOptionsArr[i].id == 'showScheduleInitDesc2'){
setTimeout(() => {
this.scheduleOptions.showScheduleInitDesc2 = true
this.scheduleOptions.scheduleActive = 2
}, this.scheduleOptionsArr[i].time)
} else if(this.scheduleOptionsArr[i].id == 'showScheduleResulteDesc1'){
setTimeout(() => {
this.scheduleOptions.showScheduleResulteDesc1 = true
}, this.scheduleOptionsArr[i].time)
} else if(this.scheduleOptionsArr[i].id == 'showScheduleResulteDesc2'){
setTimeout(() => {
this.scheduleOptions.showScheduleResulteDesc2 = true
this.scheduleOptions.scheduleActive = 3
this.simulateProgress()
}, this.scheduleOptionsArr[i].time)
}
}
},
simulateProgress() {
let intervalId = setInterval(() => {
let randomValue = Math.floor(Math.random() * 50); // 生成0-1之间的随机数
this.scheduleOptions.percentage += randomValue; // 每次增加10%的进度
if (this.scheduleOptions.percentage >= 100) {
this.scheduleOptions.percentage = 100
this.scheduleOptions.showScheduleResulteDesc3 = true
clearInterval(intervalId); // 当进度达到100%时停止定时器
}
}, 1000); // 每秒更新一次进度
}
}
}
</script>
<style lang="scss" scoped>
.el-card ::v-deep .el-card__body {
height: calc(100vh - 230px);
overflow-y: auto;
}
.style-module__grid-container--29AQk{
display: grid;
grid-template-rows: var(--template-rows);
grid-template-columns: var(--template-cols);
grid-gap: var(--gap,0);
}
.style-module__grid-item--2nHmp{
grid-row: span var(--row-span,1);
grid-column: span var(--col-span,1);
margin: 0!important;
}
.app-pts-web-card{
background-color: #fff;
box-shadow: 0 2px 4px 0 rgba(54,58,80,.32);
margin-left: auto;
margin-right: auto;
box-sizing: border-box;
border-radius: 0;
color: rgba(0,0,0,.9);
}
.app-pts-web-justify-grid{
display: flex;
width: 100%;
align-items: center;
color: rgba(0,0,0,.9);
box-sizing: border-box;
}
.app-pts-web-card__body{
font-size: 12px;
padding: 20px;
}
.app-pts-web-card{
background-color: #fff;
box-shadow: 0 2px 4px 0 rgba(54,58,80,.32);
margin-left: auto;
margin-right: auto;
box-sizing: border-box;
border-radius: 0;
color: rgba(0,0,0,.9);
}
</style>