检测计划统计功能
This commit is contained in:
@@ -69,5 +69,31 @@ export namespace Plan {
|
||||
maxTime: number;
|
||||
}
|
||||
|
||||
export interface PlanStatisticsItem {
|
||||
itemId: string;
|
||||
itemName: string;
|
||||
totalCount: number;
|
||||
qualifiedCount: number;
|
||||
unqualifiedCount: number;
|
||||
passRate: number;
|
||||
}
|
||||
|
||||
export interface PlanStatistics {
|
||||
planId: string;
|
||||
planName: string;
|
||||
totalCheckCount: number;
|
||||
checkedDeviceCount: number;
|
||||
firstQualifiedDeviceCount: number;
|
||||
secondQualifiedDeviceCount: number;
|
||||
thirdOrMoreQualifiedDeviceCount: number;
|
||||
unqualifiedDeviceCount: number;
|
||||
unqualifiedItemCount: number;
|
||||
firstPassRate: number;
|
||||
secondPassRate: number;
|
||||
thirdOrMorePassRate: number;
|
||||
unqualifiedRate: number;
|
||||
itemDistributions: PlanStatisticsItem[];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +94,10 @@ export const staticsAnalyse = (params: { id: string[] }) => {
|
||||
return http.download('/adPlan/analyse', params)
|
||||
}
|
||||
|
||||
export const getPlanStatistics = (params: { planId: string }) => {
|
||||
return http.post<Plan.PlanStatistics>(`/adPlan/statistics`, params)
|
||||
}
|
||||
|
||||
//根据计划id分页查询被检设
|
||||
export const getDevListByPlanId = (params: any) => {
|
||||
return http.post(`/adPlan/listDevByPlanId`, params)
|
||||
@@ -159,4 +163,4 @@ export const importAndMergePlanCheckData = (params: Plan.ResPlan) => {
|
||||
return http.upload(`/adPlan/importAndMergePlanCheckData`, params, {
|
||||
timeout: 60000 * 20
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
@node-click="handleNodeClick"
|
||||
>
|
||||
<template #default="{ node, data }">
|
||||
<span class="custom-tree-node" style="display: flex; align-items: center;">
|
||||
<span class="custom-tree-node">
|
||||
<!-- 父节点图标 -->
|
||||
<Platform
|
||||
v-if="!data.pid"
|
||||
@@ -39,50 +39,52 @@
|
||||
}"
|
||||
/>
|
||||
<!-- 节点名称 -->
|
||||
<span>{{ node.label }}</span>
|
||||
<!-- 子节点右侧图标 + tooltip -->
|
||||
<el-tooltip
|
||||
v-if="
|
||||
node.label != '未检' &&
|
||||
node.label != '检测中' &&
|
||||
node.label != '检测完成' &&
|
||||
hasChildrenInPlanTable(node.data)
|
||||
"
|
||||
placement="top"
|
||||
:manual="true"
|
||||
content="子计划信息"
|
||||
>
|
||||
<List
|
||||
@click.stop="childDetail(node.data)"
|
||||
style="
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-left: 8px;
|
||||
cursor: pointer;
|
||||
color: var(--el-color-primary);
|
||||
"
|
||||
<span class="node-label">{{ node.label }}</span>
|
||||
<span class="node-actions">
|
||||
<PieChart
|
||||
v-if="isCompletedPlanNode(node.data)"
|
||||
class="node-action-icon"
|
||||
@click.stop="openStatistics(node.data)"
|
||||
style="margin-right: 8px"
|
||||
/>
|
||||
</el-tooltip>
|
||||
<!-- 子节点右侧图标 + tooltip -->
|
||||
<el-tooltip
|
||||
v-if="
|
||||
node.label != '未检' &&
|
||||
node.label != '检测中' &&
|
||||
node.label != '检测完成' &&
|
||||
hasChildrenInPlanTable(node.data)
|
||||
"
|
||||
placement="top"
|
||||
:manual="true"
|
||||
content="子计划信息"
|
||||
>
|
||||
<List class="node-action-icon" @click.stop="childDetail(node.data)" />
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</span>
|
||||
</template>
|
||||
</el-tree>
|
||||
</div>
|
||||
</div>
|
||||
<SourceOpen ref="openSourceView" :width="width" :height="height + 175"></SourceOpen>
|
||||
<PlanStatisticsPopup ref="planStatisticsPopupRef" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { type Plan } from '@/api/plan/interface'
|
||||
import { List, Menu, Platform } from '@element-plus/icons-vue'
|
||||
import { List, Menu, PieChart, Platform } from '@element-plus/icons-vue'
|
||||
import { nextTick, onMounted, ref, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useCheckStore } from '@/stores/modules/check'
|
||||
import { ElTooltip } from 'element-plus'
|
||||
import SourceOpen from '@/views/plan/planList/components/childrenPlan.vue'
|
||||
import PlanStatisticsPopup from '@/views/plan/planList/components/planStatisticsPopup.vue'
|
||||
import { getPlanList } from '@/api/plan/plan.ts'
|
||||
import { useModeStore } from '@/stores/modules/mode' // 引入模式 store
|
||||
import { useDictStore } from '@/stores/modules/dict'
|
||||
|
||||
const openSourceView = ref()
|
||||
const planStatisticsPopupRef = ref<InstanceType<typeof PlanStatisticsPopup> | null>(null)
|
||||
const router = useRouter()
|
||||
const checkStore = useCheckStore()
|
||||
const filterText = ref('')
|
||||
@@ -211,6 +213,14 @@ const childDetail = (data: Plan.ResPlan) => {
|
||||
}
|
||||
}
|
||||
|
||||
const isCompletedPlanNode = (data: Partial<Plan.ResPlan>) => {
|
||||
return Number(data.testState) === 2
|
||||
}
|
||||
|
||||
const openStatistics = (data: Partial<Plan.ResPlan>) => {
|
||||
planStatisticsPopupRef.value?.open(data)
|
||||
}
|
||||
|
||||
function buildTree(flatList: any[]): any[] {
|
||||
const map = new Map()
|
||||
const tree: any[] = []
|
||||
@@ -293,6 +303,40 @@ defineExpose({ getTreeData, clickTableToTree })
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
:deep(.el-tree-node__content) {
|
||||
padding-right: 6px;
|
||||
}
|
||||
|
||||
.custom-tree-node {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.node-label {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.node-actions {
|
||||
flex: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.node-action-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
cursor: pointer;
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
//.filter-tree span {
|
||||
// font-size: 16px;
|
||||
// display:block;
|
||||
|
||||
@@ -0,0 +1,385 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="`检测计划统计 - ${planName || '/'}`"
|
||||
width="min(1280px, 92vw)"
|
||||
class="plan-statistics-dialog"
|
||||
destroy-on-close
|
||||
draggable
|
||||
@closed="handleClosed"
|
||||
>
|
||||
<div v-loading="loading" class="plan-statistics">
|
||||
<el-empty v-if="loadFailed" description="统计数据加载失败" />
|
||||
<template v-else>
|
||||
<div class="summary-grid">
|
||||
<div v-for="item in summaryItems" :key="item.label" class="summary-item">
|
||||
<span class="summary-label">{{ item.label }}</span>
|
||||
<strong class="summary-value">{{ item.value }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="isEmpty" class="empty-area">
|
||||
<el-empty description="暂无统计数据" />
|
||||
</div>
|
||||
<template v-else>
|
||||
<div class="chart-grid">
|
||||
<div class="chart-panel">
|
||||
<div class="panel-title">合格率</div>
|
||||
<div ref="rateChartRef" class="chart"></div>
|
||||
</div>
|
||||
<div class="chart-panel">
|
||||
<div class="panel-title">检测大项不合格分布</div>
|
||||
<div ref="itemChartRef" class="chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-table :data="statisticsData.itemDistributions" height="260" border>
|
||||
<el-table-column prop="itemName" label="检测大项" min-width="220" show-overflow-tooltip />
|
||||
<el-table-column prop="totalCount" label="执行次数" width="110" align="center" />
|
||||
<el-table-column prop="qualifiedCount" label="合格次数" width="110" align="center" />
|
||||
<el-table-column prop="unqualifiedCount" label="不合格次数" width="120" align="center" />
|
||||
<el-table-column label="合格率" width="110" align="center">
|
||||
<template #default="scope">{{ formatRate(scope.row.passRate) }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'
|
||||
import * as echarts from 'echarts'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { getPlanStatistics } from '@/api/plan/plan'
|
||||
import type { Plan } from '@/api/plan/interface'
|
||||
|
||||
const emptyStatistics = (): Plan.PlanStatistics => ({
|
||||
planId: '',
|
||||
planName: '',
|
||||
totalCheckCount: 0,
|
||||
checkedDeviceCount: 0,
|
||||
firstQualifiedDeviceCount: 0,
|
||||
secondQualifiedDeviceCount: 0,
|
||||
thirdOrMoreQualifiedDeviceCount: 0,
|
||||
unqualifiedDeviceCount: 0,
|
||||
unqualifiedItemCount: 0,
|
||||
firstPassRate: 0,
|
||||
secondPassRate: 0,
|
||||
thirdOrMorePassRate: 0,
|
||||
unqualifiedRate: 0,
|
||||
itemDistributions: []
|
||||
})
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const loading = ref(false)
|
||||
const loadFailed = ref(false)
|
||||
const planName = ref('')
|
||||
const rateChartRef = ref<HTMLDivElement>()
|
||||
const itemChartRef = ref<HTMLDivElement>()
|
||||
const statisticsData = reactive<Plan.PlanStatistics>(emptyStatistics())
|
||||
let rateChart: echarts.ECharts | null = null
|
||||
let itemChart: echarts.ECharts | null = null
|
||||
|
||||
const isEmpty = computed(() => {
|
||||
return (
|
||||
!loading.value &&
|
||||
statisticsData.totalCheckCount === 0 &&
|
||||
statisticsData.checkedDeviceCount === 0 &&
|
||||
statisticsData.itemDistributions.length === 0
|
||||
)
|
||||
})
|
||||
|
||||
const summaryItems = computed(() => [
|
||||
{ label: '总次数', value: statisticsData.totalCheckCount },
|
||||
{ label: '已检设备', value: statisticsData.checkedDeviceCount },
|
||||
{ label: '一次合格率', value: formatRate(statisticsData.firstPassRate) },
|
||||
{ label: '二次合格率', value: formatRate(statisticsData.secondPassRate) },
|
||||
{ label: '3次+合格率', value: formatRate(statisticsData.thirdOrMorePassRate) },
|
||||
{ label: '不合格率', value: formatRate(statisticsData.unqualifiedRate) },
|
||||
{ label: '不合格次数', value: statisticsData.unqualifiedItemCount }
|
||||
])
|
||||
|
||||
const resetData = () => {
|
||||
Object.assign(statisticsData, emptyStatistics())
|
||||
}
|
||||
|
||||
const formatRate = (value: number | string | null | undefined) => {
|
||||
const numberValue = Number(value)
|
||||
if (!Number.isFinite(numberValue)) return '0%'
|
||||
return `${numberValue.toFixed(2)}%`
|
||||
}
|
||||
|
||||
const normalizeRate = (value: number | string | null | undefined) => {
|
||||
const numberValue = Number(value)
|
||||
return Number.isFinite(numberValue) ? numberValue : 0
|
||||
}
|
||||
|
||||
const open = async (row: Partial<Plan.ReqPlan>) => {
|
||||
if (!row.id) {
|
||||
ElMessage.error('计划信息缺失,无法统计')
|
||||
return
|
||||
}
|
||||
resetData()
|
||||
disposeCharts()
|
||||
loadFailed.value = false
|
||||
planName.value = row.name || ''
|
||||
dialogVisible.value = true
|
||||
loading.value = true
|
||||
|
||||
try {
|
||||
const { data } = await getPlanStatistics({ planId: row.id })
|
||||
Object.assign(statisticsData, {
|
||||
...emptyStatistics(),
|
||||
...data,
|
||||
itemDistributions: data?.itemDistributions || []
|
||||
})
|
||||
await nextTick()
|
||||
renderCharts()
|
||||
} catch (error) {
|
||||
loadFailed.value = true
|
||||
ElMessage.error('统计数据加载失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const renderCharts = () => {
|
||||
if (!dialogVisible.value || loadFailed.value || isEmpty.value) return
|
||||
renderRateChart()
|
||||
renderItemChart()
|
||||
resizeCharts()
|
||||
}
|
||||
|
||||
const renderRateChart = () => {
|
||||
if (!rateChartRef.value) return
|
||||
rateChart?.dispose()
|
||||
rateChart = echarts.init(rateChartRef.value)
|
||||
const rateData = [
|
||||
{
|
||||
name: '一次合格率',
|
||||
value: normalizeRate(statisticsData.firstPassRate),
|
||||
count: statisticsData.firstQualifiedDeviceCount
|
||||
},
|
||||
{
|
||||
name: '二次合格率',
|
||||
value: normalizeRate(statisticsData.secondPassRate),
|
||||
count: statisticsData.secondQualifiedDeviceCount
|
||||
},
|
||||
{
|
||||
name: '三次及以上合格率',
|
||||
value: normalizeRate(statisticsData.thirdOrMorePassRate),
|
||||
count: statisticsData.thirdOrMoreQualifiedDeviceCount
|
||||
},
|
||||
{
|
||||
name: '不合格率',
|
||||
value: normalizeRate(statisticsData.unqualifiedRate),
|
||||
count: statisticsData.unqualifiedDeviceCount
|
||||
}
|
||||
]
|
||||
rateChart.setOption({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: (params: any) => {
|
||||
return `${params.name}<br/>${formatRate(params.value)}<br/>设备数:${params.data?.count || 0}`
|
||||
}
|
||||
},
|
||||
legend: { bottom: 0, left: 'center' },
|
||||
color: ['#67c23a', '#409eff', '#e6a23c', '#f56c6c'],
|
||||
series: [
|
||||
{
|
||||
name: '合格率',
|
||||
type: 'pie',
|
||||
radius: ['42%', '68%'],
|
||||
center: ['50%', '43%'],
|
||||
avoidLabelOverlap: true,
|
||||
data: rateData,
|
||||
label: {
|
||||
formatter: ({ name, value }: any) => `${name}\n${formatRate(value)}`
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
const renderItemChart = () => {
|
||||
if (!itemChartRef.value) return
|
||||
itemChart?.dispose()
|
||||
itemChart = echarts.init(itemChartRef.value)
|
||||
const topItems = [...statisticsData.itemDistributions]
|
||||
.sort((a, b) => (b.unqualifiedCount || 0) - (a.unqualifiedCount || 0))
|
||||
.slice(0, 8)
|
||||
itemChart.setOption({
|
||||
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
|
||||
grid: { left: 48, right: 20, top: 36, bottom: 48 },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: topItems.map(item => item.itemName || '/'),
|
||||
axisLabel: { interval: 0, rotate: 28 }
|
||||
},
|
||||
yAxis: { type: 'value', minInterval: 1 },
|
||||
series: [
|
||||
{
|
||||
name: '不合格次数',
|
||||
type: 'bar',
|
||||
barWidth: 30,
|
||||
data: topItems.map(item => item.unqualifiedCount || 0),
|
||||
itemStyle: { color: '#f56c6c' }
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
const disposeCharts = () => {
|
||||
rateChart?.dispose()
|
||||
itemChart?.dispose()
|
||||
rateChart = null
|
||||
itemChart = null
|
||||
}
|
||||
|
||||
const resizeCharts = () => {
|
||||
rateChart?.resize()
|
||||
itemChart?.resize()
|
||||
}
|
||||
|
||||
const handleClosed = () => {
|
||||
disposeCharts()
|
||||
resetData()
|
||||
loadFailed.value = false
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('resize', resizeCharts)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', resizeCharts)
|
||||
disposeCharts()
|
||||
})
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.plan-statistics-dialog) {
|
||||
max-width: 92vw;
|
||||
}
|
||||
|
||||
:deep(.plan-statistics-dialog .el-dialog__body) {
|
||||
padding: 14px;
|
||||
}
|
||||
|
||||
.plan-statistics {
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.summary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.summary-item {
|
||||
min-height: 64px;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--el-border-color-light);
|
||||
border-radius: 6px;
|
||||
background: var(--el-fill-color-lighter);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.summary-label {
|
||||
display: block;
|
||||
color: var(--el-text-color-secondary);
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.summary-value {
|
||||
display: block;
|
||||
margin-top: 6px;
|
||||
color: var(--el-text-color-primary);
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.chart-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.chart-panel {
|
||||
border: 1px solid var(--el-border-color-light);
|
||||
border-radius: 6px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
color: var(--el-text-color-primary);
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.chart {
|
||||
width: 100%;
|
||||
height: 250px;
|
||||
}
|
||||
|
||||
.empty-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 320px;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.summary-grid {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.summary-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.chart-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.chart {
|
||||
height: 260px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
:deep(.plan-statistics-dialog) {
|
||||
width: 96vw;
|
||||
max-width: 96vw;
|
||||
}
|
||||
|
||||
:deep(.plan-statistics-dialog .el-dialog__body) {
|
||||
max-height: calc(92vh - 110px);
|
||||
overflow-y: auto;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.summary-grid {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.summary-item {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.summary-value {
|
||||
font-size: 18px;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -99,6 +99,16 @@
|
||||
被检设备
|
||||
</el-button>
|
||||
<!-- <el-button type='primary' link :icon='List' @click='showDeviceOpen(scope.row)'>设备绑定</el-button> -->
|
||||
<el-button
|
||||
type="primary"
|
||||
v-auth.plan="'analysis'"
|
||||
link
|
||||
icon="PieChart"
|
||||
v-if="scope.row.testState == '2' && modeStore.currentMode != '比对式'"
|
||||
@click="openStatistics(scope.row)"
|
||||
>
|
||||
统计
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
v-auth.plan="'analysis'"
|
||||
@@ -136,6 +146,7 @@
|
||||
|
||||
<ImportExcel ref="planImportExcel" />
|
||||
<ImportZip ref="planImportZip" @result="importResult" />
|
||||
<PlanStatisticsPopup ref="planStatisticsPopupRef" />
|
||||
|
||||
<ChildrenPlan
|
||||
:refresh-table="refreshTable"
|
||||
@@ -163,6 +174,7 @@ import { computed, onMounted, reactive, ref, watch } from 'vue'
|
||||
import type { Plan } from '@/api/plan/interface'
|
||||
import PlanPopup from '@/views/plan/planList/components/planPopup.vue' // 导入子组件
|
||||
import ChildrenPlan from '@/views/plan/planList/components/childrenPlan.vue'
|
||||
import PlanStatisticsPopup from '@/views/plan/planList/components/planStatisticsPopup.vue'
|
||||
import { useViewSize } from '@/hooks/useViewSize'
|
||||
import { useDictStore } from '@/stores/modules/dict'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
@@ -187,6 +199,7 @@ const proTable = ref<ProTableInstance>()
|
||||
const errorStandardPopup = ref()
|
||||
const testSourcePopup = ref()
|
||||
const planPopup = ref()
|
||||
const planStatisticsPopupRef = ref<InstanceType<typeof PlanStatisticsPopup> | null>(null)
|
||||
|
||||
const modeStore = useModeStore()
|
||||
const tableData = ref<any[]>([])
|
||||
@@ -530,7 +543,7 @@ const columns = reactive<ColumnProps<Plan.ReqPlan>[]>([
|
||||
isShow: modeStore.currentMode == '比对式'
|
||||
},
|
||||
|
||||
{ prop: 'operation', label: '操作', fixed: 'right', minWidth: 250 }
|
||||
{ prop: 'operation', label: '操作', fixed: 'right', minWidth: 320 }
|
||||
])
|
||||
|
||||
function isVisible(row: Plan.ReqPlan) {
|
||||
@@ -654,6 +667,10 @@ const statisticalAnalysis = async (row: Partial<Plan.ReqPlan> = {}) => {
|
||||
useDownload(staticsAnalyse, '分析结果', [row.id], false, '.xlsx')
|
||||
}
|
||||
|
||||
const openStatistics = (row: Partial<Plan.ReqPlan> = {}) => {
|
||||
planStatisticsPopupRef.value?.open(row)
|
||||
}
|
||||
|
||||
const importSubClick = () => {
|
||||
const params = {
|
||||
title: '导入检测计划',
|
||||
@@ -671,4 +688,4 @@ const importResult = async (success: boolean | undefined) => {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped></style>
|
||||
|
||||
Reference in New Issue
Block a user