Files
pqs-9100_client/frontend/src/views/home/tabs/dashboard.vue
2025-01-15 13:46:11 +08:00

697 lines
21 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>
<div class='static'>
<el-row :gutter='10'>
<el-col :lg='4' :xl='4' :md='4' :sm='4'>
<div class='left_tree'>
<tree ref='treeRef' :updateSelectedTreeNode='getPieData || (() => {})' />
</div>
</el-col>
<el-col :lg='20' :xl='20' :md='20' :sm='20'>
<div class='right_container'>
<!-- 功能选择 -->
<div class='container_function'>
<div
class='function_item'
:class="item.checked ? 'function_item checked_function' : 'function_item'"
v-for='(item, index) in tabsList'
:key='index'
@click='handleCheckFunction(item.value)'
>
<div class='item_img'>
<img :src='item.img' />
</div>
<div class='item_text'>
<p>{{ item.label }}</p>
</div>
</div>
</div>
<!--检测计划统计 饼图统计-->
<div class='container_pieShow'>
<el-collapse model-value='1' accordion @change='handleCollapseChange'>
<el-collapse-item name='1'>
<template #title>
<div class='container_pieShow_title'>
<span>检测计划统计</span>
<span>{{ planName }}</span>
</div>
</template>
<!-- 饼图 -->
<div class='container_charts'>
<div class='charts_info' ref='chartsInfoRef'>
<pie
:customData="{
title: '设备检测状态',
textAlign: 'left',
}"
:legendData="{
icon: 'circle',
left: 'left',
top: 'bottom',
}"
:chartsData='chartsData1'
ref='pieRef1'
></pie>
</div>
<div class='charts_info'>
<pie
:customData="{
title: '设备检测结果',
textAlign: 'left',
}"
:legendData="{
icon: 'circle',
left: 'left',
top: 'bottom',
}"
:chartsData='chartsData2'
ref='pieRef2'
></pie>
</div>
<div class='charts_info'>
<pie
:customData="{
title: '设备报告状态',
textAlign: 'left',
}"
:legendData="{
icon: 'circle',
left: 'left',
top: 'bottom',
}"
:chartsData='chartsData3'
ref='pieRef3'
></pie>
</div>
</div>
</el-collapse-item>
</el-collapse>
</div>
<!--下方表格数据-->
<el-tabs class='tabs-menu' type='border-card' @tab-change='handleTabsChange' v-model='editableTabsValue'
:style='{ height: tabsHeight }'>
<el-tab-pane :label='tabLabel1' :style='{ height: tabPaneHeight}'>
<!-- 列表数据 -->
<div class='container_table' :style='{ height: tableHeight }'>
<Table ref='tableRef1' :id='currentId' :isTimeCheck='isTimeCheck' :plan = 'select_Plan' @batchGenerateClicked="handleBatchGenerate"></Table>
</div>
</el-tab-pane>
</el-tabs>
</div>
</el-col>
</el-row>
</div>
</template>
<script lang='ts' setup>
import pie from '@/components/echarts/pie/default.vue'
import { useRouter } from 'vue-router'
import tree from '../components/tree.vue'
import Table from '../components/table.vue'
import deviceDataList from '@/api/device/device/deviceData'
import { getBoundPqDevList, getPlanListByPattern } from '@/api/plan/plan.ts'
import { onBeforeMount, onUnmounted, ref, watch } from 'vue'
import { useModeStore } from '@/stores/modules/mode' // 引入模式 store
import { useDictStore } from '@/stores/modules/dict'
import { type Plan } from '@/api/plan/interface'
import type { CollapseModelValue } from 'element-plus/es/components/collapse/src/collapse.mjs'
import { type Device } from '@/api/device/interface/device'
import { ResultData } from '@/api/interface'
const planName = ref('')
const dictStore = useDictStore()
const modeStore = useModeStore()
const chartsInfoRef = ref<HTMLElement | null>(null)
const chartsWidth = ref<number>(0)
const deviceData = deviceDataList.plan_devicedata
const treeRef = ref()
const form: any = ref({
activeTabs: 0, //功能选择,例如报告生成
activeChildTabs: 0,//子功能选择,例如未检设备报告生成,或已检设备更换误差体系生成
checkStatus: 0, //检测状态
checkReportStatus: 0, //检测报告状态
checkResult: 0, //检测结果
deviceBindStatus: 0, //绑定状态
deviceType: 0, //设备类型
manufacturer: 0, //制造厂商
})
const router = useRouter()
const tabShow = ref(false)
const tabLabel1 = ref('设备检测')
const editableTabsValue = ref('0')
const checkStateTable = ref<number[]>([0, 1, 2])
const tabsHeight = ref('calc(100vh - 522px)') // 初始高度
const tabPaneHeight = ref('calc(100% - 5px)') // 初始高度
const tableHeight = ref('calc(100% - 50px)') // 初始高度
const isTimeCheck = ref<boolean>(false)
const planList = ref<ResultData<Plan.ReqPlan[]>>()
const select_Plan = ref<Plan.ReqPlan>()
const handleCollapseChange = (val: CollapseModelValue) => {
// 计算新的高度
let newHeight
if (Array.isArray(val)) {
newHeight = val.length > 0 ? 'calc(100vh - 522px)' : 'calc(100vh - 333px)'
} else {
newHeight = val ? 'calc(100vh - 538px)' : 'calc(100vh - 333px)'
}
tabsHeight.value = newHeight
tabPaneHeight.value = `calc(100% - 5px)`
tableHeight.value = `calc(100% - 5px)`
}
const handleTabsChange = (val: any) => {
form.value.activeTabs = 0
form.value.activeTabs = 3
form.value.activeChildTabs = Number(val)
}
localStorage.setItem('color', 'red')
//功能选择数据
const tabsList = ref([
{
label: '设备检测',
value: 0,
img: new URL('/src/assets/images/plan/static/1.svg', import.meta.url).href,
checked: true,
},
{
label: '报告生成',
value: 3,
img: new URL('/src/assets/images/plan/static/3.svg', import.meta.url).href,
checked: false,
},
{
label: '设备归档',
value: 4,
img: new URL('/src/assets/images/plan/static/4.svg', import.meta.url).href,
checked: false,
},
{
label: '数据操作',
value: 5,
img: new URL('/src/assets/images/plan/static/5.svg', import.meta.url).href,
checked: false,
},
])
form.value.activeTabs = tabsList.value[0].value
const tableRef1 = ref()
const tableRef2 = ref()
const currentId = ref('')
watch(
() => form.value,
(val, oldVal) => {
if (val) {
if (form.value.activeTabs === 0)//设备检测
{
const tabledata = deviceData.filter((item) => item.document_State === '未归档')
tableRef1.value && tableRef1.value.changeActiveTabs(form.value.activeTabs, form.value.activeChildTabs, tabledata)
} else if (form.value.activeTabs === 4)//设备归档
{
const tabledata = deviceData.filter((item) => item.check_State === '检测完成' && item.document_State === '未归档')
tableRef1.value && tableRef1.value.changeActiveTabs(form.value.activeTabs, form.value.activeChildTabs, tabledata)
} else if (form.value.activeTabs === 3 || form.value.activeTabs === 5)//报告生成、数据查询
{
const tabledata = deviceData.filter((item) => item.check_State === '检测完成')
tableRef1.value && tableRef1.value.changeActiveTabs(form.value.activeTabs, form.value.activeChildTabs, tabledata)
}
}
},
{
immediate: true,
deep: true,
},
)
watch(
() => form.value,
(val, oldVal) => {
if (val) {
tableRef2.value && tableRef2.value.changeActiveTabs(form.value.activeTabs, form.value.activeChildTabs)
}
},
{
immediate: true,
deep: true,
},
)
const pieRef1 = ref(),
pieRef2 = ref(),
pieRef3 = ref()
const chartsData1: any = ref([]),
chartsData2: any = ref([]),
chartsData3: any = ref([])
const findPlanById = (plans: Plan.ReqPlan[], id: string): Plan.ReqPlan | undefined => {
for (const plan of plans) {
if (plan.id === id) {
return plan
}
if (plan.children) {
const foundPlan = findPlanById(plan.children, id)
if (foundPlan) {
return foundPlan
}
}
}
return undefined
}
const getPieData = async (id: string) => {
currentId.value = id // 设置当前ID
// 初始化计数对象
const checkStateCount: { [key: number]: number } = { 0: 0, 1: 0, 2: 0, 3: 0 }
const checkResultCount: { [key: number]: number } = { 0: 0, 1: 0, 2: 0 }
const reportStateCount: { [key: number]: number } = { 0: 0, 1: 0, 2: 0 }
if (id) {
const boundPqDevList = ref<Device.ResPqDev[]>([])//根据检测计划id查询出所有已绑定的设备
const plan = findPlanById(planList.value?.data || [], id)
planName.value = '所选计划:' + plan.name
//获取点击树的父节点名字
const parentNodeName = ref('')
for (let i = 0; i < planList.value.data.length; i++) {
if (Array.isArray(planList.value.data[i].children) && planList.value.data[i].children.length > 0) {
for (let j = 0; j < planList.value.data[i].children.length; j++) {
if (planList.value.data[i].children[j].id === id) {
parentNodeName.value = planList.value.data[i].name
break;
}
}
}
}
if(parentNodeName.value === '检测完成'){
handleCheckFunction(5)
}else{
handleCheckFunction(0)
}
select_Plan.value = plan
if (plan) {
//isTimeCheck.value = plan.timeCheck === 1; // 将 1 转换为 true0 转换为 false
isTimeCheck.value = false // 将 1 转换为 true0 转换为 false ----目前不用守时检测,先去除
} else {
// 处理未找到计划的情况
isTimeCheck.value = false // 或者其他默认值
}
const pqDevList_Result2 = await getBoundPqDevList({ 'planId': id, 'checkStateList': [0, 1, 2, 3] })
boundPqDevList.value = pqDevList_Result2.data as Device.ResPqDev[]
// 遍历 boundPqDevList 并更新计数对象
boundPqDevList.value.forEach(t => {
if (t.checkState !== undefined && t.checkState !== null && checkStateCount[t.checkState] !== undefined) {
checkStateCount[t.checkState]++
}
})
boundPqDevList.value.forEach(t => {
if (t.checkResult !== undefined && t.checkResult !== null && checkResultCount[t.checkResult] !== undefined) {
checkResultCount[t.checkResult]++
}
})
boundPqDevList.value.forEach(t => {
if (t.reportState !== undefined && t.reportState !== null && reportStateCount[t.reportState] !== undefined) {
reportStateCount[t.reportState]++
}
})
// 检查 checkStateCount 是否全为 0
const allZero = Object.values(checkStateCount).every(count => count === 0);
chartsData1.value = [
{ value: allZero ? 0 : checkStateCount[0] === 0 ? null : checkStateCount[0], name: '未检', itemStyle: { color: '#fac858' } },
{ value: allZero ? 0 : checkStateCount[1] === 0 ? null : checkStateCount[1], name: '检测中', itemStyle: { color: '#ee6666' } },
{ value: allZero ? 0 : checkStateCount[2] === 0 ? null : checkStateCount[2], name: '检测完成', itemStyle: { color: '#91cc75' } },
{ value: allZero ? 0 : checkStateCount[3] === 0 ? null : checkStateCount[3], name: '归档', itemStyle: { color: '#5470c6' } },
];
// 同样处理 chartsData2 和 chartsData3
const allZeroResult = Object.values(checkResultCount).every(count => count === 0);
chartsData2.value = [
{ value: allZeroResult ? 0 : checkResultCount[2] === 0 ? null : checkResultCount[2], name: '未检', itemStyle: { color: '#fac858' } },
{ value: allZeroResult ? 0 : checkResultCount[0] === 0 ? null : checkResultCount[0], name: '不符合', itemStyle: { color: '#ee6666' } },
{ value: allZeroResult ? 0 : checkResultCount[1] === 0 ? null : checkResultCount[1], name: '符合', itemStyle: { color: '#91cc75' } },
];
// 检查 reportStateCount 是否全为 0
const allZeroReport = Object.values(reportStateCount).every(count => count === 0);
chartsData3.value = [
{ value: allZeroReport ? 0 : reportStateCount[2] === 0 ? null : reportStateCount[2], name: '未检', itemStyle: { color: '#fac858' } },
{ value: allZeroReport ? 0 : reportStateCount[0] === 0 ? null : reportStateCount[0], name: '未生成', itemStyle: { color: '#ee6666' } },
{ value: allZeroReport ? 0 : reportStateCount[1] === 0 ? null : reportStateCount[1], name: '已生成', itemStyle: { color: '#91cc75' } },
];
}else{
planName.value = '所选计划:'
}
pieRef1.value.init()
pieRef2.value.init()
pieRef3.value.init()
}
const getTree = (data?: any) => {
treeRef.value.getTreeData(data)
}
//前往检测
const handleDetection = () => {
router.push({
path: '/detection',
})
}
//前往计划详情
const planDetail = () => {
router.push({
path: '/plan/planList',
})
}
//功能选择css切换
const handleCheckFunction = (val: any) => {
editableTabsValue.value = '0'
form.value.activeChildTabs = 0
tabsList.value.map((item: any, index: any) => {
if (val == item.value) {
item.checked = true
} else {
item.checked = false
}
})
tabShow.value = false
switch (val) {
case 0://自动检测
checkStateTable.value = [0, 1, 2]
tabLabel1.value = '设备检测'
break
case 1://手动检测
tabLabel1.value = '手动检测'
break
case 2://设备复检
tabLabel1.value = '设备复检'
break
case 3://报告生成
checkStateTable.value = [2, 3]
tabLabel1.value = '报告生成'
//tabShow.value = true;
break
case 4://设备归档
checkStateTable.value = [2]
tabLabel1.value = '设备归档'
break
case 5://数据查询
checkStateTable.value = [2, 3]
tabLabel1.value = '数据查询'
break
}
form.value.activeTabs = val
}
const resizeObserver = new ResizeObserver(entries => {
for (let entry of entries) {
chartsWidth.value = entry.contentRect.width
//console.log('Charts Info Width:', chartsWidth.value);
pieRef1.value?.reSize(chartsWidth.value * 0.95, 180, true)
pieRef2.value?.reSize(chartsWidth.value * 0.95, 180, true)
pieRef3.value?.reSize(chartsWidth.value * 0.95, 180, true)
}
})
onBeforeMount(async () => {
const patternId = dictStore.getDictData('Pattern').find(item => item.name === modeStore.currentMode)?.id ?? ''//获取数据字典中对应的id
const reqPlan: Plan.ReqPlan = {
pattern: patternId,
datasourceIds: '',
sourceIds: '',
planId: '',
scriptName: '',
errorSysName: '',
sourceName: '',
devIds: [],
id: '',
name: '',
dataSourceId: '',
scriptId: '',
errorSysId: '',
timeCheck: 0,
testState: 0,
reportState: 0,
result: 0,
code: 0,
state: 0,
}
planList.value = (await getPlanListByPattern(reqPlan)) as ResultData<Plan.ReqPlan[]>
console.log(planList.value.data)
for (let i = 0; i < planList.value.data.length; i++) {
if (Array.isArray(planList.value.data[i].children) && planList.value.data[i].children.length > 0) {
currentId.value = planList.value.data[i].children[0].id; // 直接赋值第一个 children 的 id
break; // 确保只执行一次
}
}
// if (planList.value.data[0].children[0]) {
// currentId.value = planList.value.data[0].children[0].id
// console.log('currentId.value',planList.value.data[0])
// }
if (chartsInfoRef.value) {
resizeObserver.observe(chartsInfoRef.value)
}
getTree(planList.value.data)
getPieData(currentId.value)
})
onUnmounted(() => {
if (chartsInfoRef.value) {
resizeObserver.unobserve(chartsInfoRef.value)
}
})
const handleBatchGenerate = () => {
console.log('批量生成按钮被点击了');
// 在这里添加其他逻辑,比如显示对话框、更新状态等
getPieData(currentId.value)
if (form.value.activeTabs === 0)//设备检测
{
const tabledata = deviceData.filter((item) => item.document_State === '未归档')
tableRef1.value && tableRef1.value.changeActiveTabs(form.value.activeTabs, form.value.activeChildTabs, tabledata)
} else if (form.value.activeTabs === 4)//设备归档
{
const tabledata = deviceData.filter((item) => item.check_State === '检测完成' && item.document_State === '未归档')
tableRef1.value && tableRef1.value.changeActiveTabs(form.value.activeTabs, form.value.activeChildTabs, tabledata)
} else if (form.value.activeTabs === 3 || form.value.activeTabs === 5)//报告生成、数据查询
{
const tabledata = deviceData.filter((item) => item.check_State === '检测完成')
tableRef1.value && tableRef1.value.changeActiveTabs(form.value.activeTabs, form.value.activeChildTabs, tabledata)
}
};
</script>
<style lang='scss' scoped>
.static {
.left_tree {
height: 100%;
background-color: #fff;
}
.right_container {
flex: none;
height: 100%;
display: flex;
flex-direction: column;
.container_function {
width: 100%;
height: auto;
background: #fff;
border-radius: 4px;
display: flex;
justify-content: flex-start;
align-items: center;
margin-bottom: 10px;
padding: 10px 20px 10px 20px;
box-sizing: border-box;
.function_item {
flex: none;
width: 6%;
height: 70px;
display: flex;
justify-content: space-between;
align-items: center;
flex-direction: column;
cursor: pointer;
background-color: #607eab;
border-radius: 8px;
padding: 0px 30px;
margin-right: 50px;;
.item_img {
width: 60px;
height: 60px;
border-radius: 50%;
// background-color: #607eab;
display: flex;
align-items: center;
justify-content: center;
img {
width: 40px;
height: auto;
}
}
.item_img:nth-child(3),
.item_img:nth-child(6) {
padding: 10px !important;
img {
width: 20px !important;
height: auto;
}
}
.item_text {
p {
margin: 0;
font-weight: 800;
color: #fff;
font-size: 14px;
font-family: "Microsoft YaHei", "微软雅黑", "Arial", sans-serif;
}
}
}
.function_item:hover,
.checked_function {
background-color: var(--el-color-primary);
.item_img {
// background-color: var(--el-color-primary);
}
.item_text {
p {
// color: var(--el-color-primary);
color: #fff;
}
}
}
}
.container_pieShow {
width: 100% !important;
height: auto;
background-color: #eee;
margin-bottom: 10px;
.container_pieShow_title {
display: flex;
justify-content: space-between;
padding: 0 15px;
font-weight: bold;
width: 100%;
font-size: 14px;
}
}
.el-collapse {
width: 100% !important;
height: 100% !important;
background-color: #eee;
}
.el-collapse-item {
width: 100% !important;
height: 100% !important;
background-color: #eee;
}
.container_charts {
width: 100%;
height: 100%;
background-color: #eee;
display: flex;
justify-content: space-between;
.charts_info {
margin-top: 1px;
flex: none;
width: 33.1%;
height: 100% !important;
background-color: #fff;
}
}
.el-tabs {
width: 100% !important;
border-radius: 4px;
}
.tabs-menu {
height: 100%;
border: 0;
}
.container_table {
// width: 100%;
flex: 1 !important;
//height: calc(100vh - 360px - 180px);
height: 100% !important;
border-radius: 4px;
width: 100% !important;
// display: none;
.table_info {
width: 100%;
height: 100%;
}
}
}
}
:deep(.el-collapse-item__header) {
color: var(--el-color-primary);
font-size: 14px;
font-family: "Microsoft YaHei", "微软雅黑", "Arial", sans-serif;
}
:deep(.el-collapse-item__conten) {
padding-bottom: 0px !important;
}
:deep(.el-collapse-item__content ) {
padding-bottom: 0px !important;
}
:deep(.el-tabs--border-card > .el-tabs__content) {
padding: 0 !important;
}
</style>