map/ui/dasadmin/src/views/backend/malfunction/index.vue

1100 lines
38 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="malfunction">
<el-container class="container">
<el-aside class="aside">
<div class="searchTree">
<el-input v-model="searchTreeValue" clearable placeholder="搜索" :suffix-icon="Search" @change="searchTree"> </el-input>
</div>
<div class="treeMain">
<el-scrollbar>
<el-tree
ref="treeRef"
highlight-current
:data="treeData"
:props="defaultProps"
node-key="id"
:default-expanded-keys="defaultExpandKeys"
@node-click="handleNodeClick"
@node-contextmenu="rightClick"
></el-tree>
</el-scrollbar>
</div>
</el-aside>
<el-container class="mainContainer">
<el-header class="header">
<div class="searchFileName">
<span>文件名称</span>
<el-input v-model="searchData.fileName"></el-input>
</div>
<div class="searchDate">
<span>日期</span>
<el-date-picker
v-model="searchData.date"
type="daterange"
unlink-panels
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD"
date-format="YYYY/MM/DD"
:shortcuts="shortcuts"
@change="getListForAirBlower"
></el-date-picker>
</div>
<div class="btnPart">
<!-- <el-button type="primary" v-show="curTreeData.id !== '0'" :icon="Setting" @click="openConfigDialog">配置</el-button> -->
<!--
<el-button type="primary" :icon="Download">下载</el-button>
<el-button type="primary" plain :icon="Delete">删除</el-button>
-->
</div>
</el-header>
<el-main class="main">
<el-tabs v-model="activeName" @tab-change="checkTab" class="tabs">
<el-tab-pane label="故障录波文件" name="malFunction" class="tabPane">
<div class="tableMain">
<el-table :data="tableData" class="tableClass">
<el-table-column type="selection" width="55" />
<el-table-column label="文件名称" prop="name" align="center"></el-table-column>
<el-table-column label="修改时间" prop="lastModified" align="center" width="250"></el-table-column>
<el-table-column label="文件大小" prop="size" align="center" width="120"></el-table-column>
<el-table-column label="操作" align="center" width="140">
<template #default="scope">
<div class="tableBtnPart">
<el-button text type="primary" @click="readFile(scope.row)">查看</el-button>
<el-button text type="danger" @click="downloadFile(scope.row)">下载</el-button>
</div>
</template>
</el-table-column>
</el-table>
</div>
<div class="footerPart">
<el-pagination
v-model:current-page="pageSetting.current"
v-model:page-size="pageSetting.pageSize"
:total="pageSetting.total"
:page-sizes="pageSetting.pageSizes"
background
:pager-count="7"
layout="total,prev, pager, next, jumper,sizes"
@change="changePageSetting"
></el-pagination>
</div>
</el-tab-pane>
<el-tab-pane label="运行日志文件" name="logManage" class="tabPane">
<div class="tableMain">
<el-table :data="logTableData" class="tableClass">
<el-table-column type="selection" width="55" />
<el-table-column label="文件名称" prop="name" align="center"></el-table-column>
<el-table-column label="修改时间" prop="lastModified" align="center" width="250"></el-table-column>
<el-table-column label="文件大小" prop="size" align="center" width="120"></el-table-column>
<el-table-column label="操作" align="center" width="140">
<template #default="scope">
<div class="tableBtnPart">
<el-button text type="primary" @click="readFile(scope.row)">查看</el-button>
<el-button text type="danger" @click="downloadFile(scope.row)">下载</el-button>
</div>
</template>
</el-table-column>
</el-table>
</div>
<div class="footerPart">
<el-pagination
v-model:current-page="logPageSetting.current"
v-model:page-size="logPageSetting.pageSize"
:total="logPageSetting.total"
:page-sizes="logPageSetting.pageSizes"
background
:pager-count="7"
layout="total,prev, pager, next, jumper,sizes"
@change="changePageSetting"
></el-pagination>
</div>
</el-tab-pane>
</el-tabs>
</el-main>
</el-container>
</el-container>
<el-dialog v-model="configDialogVisible" title="配置信息" width="500" @close="closeConfigDialog">
<el-form ref="configFormRef" :model="configFormData" label-width="120" :rules="configFormRules">
<el-form-item prop="timeFormat" label="时间格式">
<el-input v-model="configFormData.timeFormat"></el-input>
</el-form-item>
<el-form-item prop="delimiter" label="分隔符">
<el-input v-model="configFormData.delimiter"></el-input>
</el-form-item>
<el-form-item prop="validStartLine" label="有效起始行数">
<el-input-number v-model="configFormData.validStartLine"></el-input-number>
</el-form-item>
</el-form>
<template #footer>
<el-button type="primary" @click="submitConfig">保存</el-button>
<el-button @click="cancelConfig">取消</el-button>
</template>
</el-dialog>
<el-dialog v-model="previewFileDialogVisible" title="数据分析" width="1000" @close="closePreviewFileDialog">
<el-row class="previewFilePart">
<el-col :span="8" class="colPart leftCol" v-loading="previewTreeLoading">
<div class="search">
<el-input
v-model="previewSearchTreeVal"
@change="previewSearchTree"
class="previewSearchTree"
:suffix-icon="Search"
clearable
></el-input>
<el-button @click="clearPreviewTree">清空</el-button>
</div>
<el-scrollbar class="previewTreeScrollbar">
<el-tree
ref="previewTreeRef"
:data="previewTreeData"
:props="previewTreeProps"
show-checkbox
node-key="key"
@check="handleCheckChange"
></el-tree>
<!--
@node-click="previewNodeClick"
-->
</el-scrollbar>
</el-col>
<el-col :span="16" class="colPart">
<div class="title">{{ fileName }}</div>
<div class="chartPart">
<div ref="previewChartRef" class="previewChart"></div>
</div>
</el-col>
</el-row>
</el-dialog>
<ContextMenu v-model:visible="contextMenuInfo.visible" :pos="contextMenuInfo.pos">
<template #default>
<div class="contextMenuBtns">
<el-button size="small" @click="openConfigDialog('malFunction')">故障录波配置</el-button>
<el-button size="small" @click="openConfigDialog('logManage')">运行日志配置</el-button>
</div>
</template>
</ContextMenu>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, computed, onMounted, nextTick, onUnmounted } from 'vue'
import { dayjs, ElMessage, FormInstance, TreeInstance } from 'element-plus'
import { Search, Setting } from '@element-plus/icons-vue'
import { getMalFunctionListReq, setConfigReq, previewFileReq, downloadFileReq, getFileKeyEnumsReq } from '/@/api/backend/malfunction/request'
import {
getLogRecordListReq,
setConfigReq as setLogConfigReq,
previewFileReq as previewLogFileReq,
downloadFileReq as downloadLogFileReq,
getFileKeyEnumsReq as getLogFileKeyEnumsReq,
} from '/@/api/backend/logRecord/request'
import { equipList } from '/@/api/backend/temperature/request'
import * as echarts from 'echarts'
import { tableItemData } from './type'
import ContextMenu from '/@/views/backend/auth/model/contextMenu.vue'
import { useRouter, useRoute } from 'vue-router'
const route = useRoute()
const defaultProps = {
children: 'children',
label: 'label',
}
const contextMenuInfo = reactive({
visible: false,
pos: {
x: 0,
y: 0,
},
})
const treeRef = ref()
let originTreeChildData: {
label: string
id: string
code: string
children?: any[]
}[] = []
const treeData = ref<
{
label: string
id: string
code: string
options: any
children?: any[]
}[]
>([
{
label: '风机列表',
id: '0',
code: '0',
options: {},
children: [],
},
])
const defaultExpandKeys: string[] = ['0']
const searchTreeValue = ref('')
const searchTree = (val: string) => {
if (val == '') {
treeData.value[0].children = originTreeChildData
return
}
const reg = new RegExp(val, 'i')
treeData.value[0].children =
originTreeChildData.filter((item: any) => {
return reg.test(item.label)
}) ?? []
}
const curTreeData = ref<{
label: string
id: string
code: string
model: string
madeinFactory: string
options: any
children?: any[]
}>({
label: '风机列表',
id: '0',
code: '0',
model: '',
madeinFactory: '',
options: {},
})
const handleNodeClick = (target: { label: string; id: string; code: string; model: string; madeinFactory: string; options: any }) => {
curTreeData.value = target
if (target.id === '0') return
getListForAirBlower()
}
const rightClickData = ref()
const rightClick = (
event: any,
data: {
label: string
id: string
code: string
model: string
madeinFactory: string
options: any
children?: any[]
}
) => {
rightClickData.value = data
contextMenuInfo.visible = true
contextMenuInfo.pos = {
x: event.clientX,
y: event.clientY,
}
}
const getTreeDataList = () => {
return new Promise((resolve) => {
equipList({ objectType: 10002 }).then((res) => {
const data = res.data.map((item: any) => {
return {
label: item.name,
code: item.code,
id: item.id,
model: item.model,
madeinFactory: item.madeinFactory,
options: item.options ? JSON.parse(item.options) : {},
}
})
originTreeChildData = data
treeData.value[0].children = data
resolve(data[0])
})
})
}
const initDatestart = route.query.eventTime ? dayjs(Number(route.query.eventTime)) : dayjs().startOf('month')
const initDateend = route.query.eventTime ? dayjs(Number(route.query.eventTime)) : dayjs()
const searchData = reactive<{ fileName: ''; date: Date[] }>({
fileName: '',
date: [initDatestart.toDate(), initDateend.toDate()],
})
const shortcuts = [
{
text: '本月',
value: () => {
const start = dayjs().startOf('month').toDate()
const end = dayjs().endOf('month').toDate()
return [start, end]
},
},
{
text: '上月',
value: () => {
const start = dayjs().subtract(1, 'month').startOf('month').toDate()
const end = dayjs().subtract(1, 'month').endOf('month').toDate()
return [start, end]
},
},
{
text: '近三月',
value: () => {
const start = dayjs().subtract(2, 'month').startOf('month').toDate()
const end = dayjs().toDate()
return [start, end]
},
},
]
let originTableData = ref<tableItemData[]>([])
const tableData = computed(() => {
let data = originTableData.value
if (searchData.fileName) {
const reg = new RegExp(searchData.fileName, 'i')
data = data.filter((item) => reg.test(item.name))
}
const res = data.slice((pageSetting.current - 1) * pageSetting.pageSize, pageSetting.current * pageSetting.pageSize)
pageSetting.total = res.length
return res
})
const pageSetting = reactive({
current: 1,
pageSize: 20,
total: 0,
pageSizes: [20, 50, 100],
})
const changePageSetting = () => {}
const getListForAirBlower = () => {
const data = {
deviceCode: curTreeData.value.code,
startTime: dayjs(searchData.date[0]).format('YYYY-MM-DD'),
endTime: dayjs(searchData.date[1]).format('YYYY-MM-DD'),
}
if (activeName.value === 'malFunction') {
getMalFunctionListReq(data).then((res) => {
if (res.success) {
pageSetting.total = res.data.length
originTableData.value = res.data
}
})
} else if (activeName.value === 'logManage') {
getLogRecordListReq(data).then((res) => {
if (res.success) {
logPageSetting.total = res.data.length
logOriginTableData.value = res.data
}
})
}
}
const configDialogVisible = ref(false)
const configFormRef = ref<FormInstance>()
const closeConfigDialog = () => {
configFormRef.value?.resetFields()
}
const configFormData = reactive({
timeFormat: '',
delimiter: '',
validStartLine: 4,
})
const defaultConfigData = {
plcTimeFormat: 'dd.MM.yyyy HH:mm:ss,SSS',
plcDelimiter: '\t',
plcValidStartLine: 12,
fdrTimeFormat: 'yyyy-MM-dd_HH-mm-ss.SSS',
fdrDelimiter: ';',
fdrValidStartLine: 7,
}
const setConfigType = ref<'malFunction' | 'logManage'>('malFunction')
const openConfigDialog = (type: 'malFunction' | 'logManage') => {
configDialogVisible.value = true
setConfigType.value = type
if (type === 'malFunction') {
configFormData.delimiter = rightClickData.value.options?.fdrFormat?.delimiter ?? defaultConfigData.fdrDelimiter
configFormData.timeFormat = rightClickData.value.options?.fdrFormat?.timeFormat ?? defaultConfigData.fdrTimeFormat
configFormData.validStartLine = rightClickData.value.options?.fdrFormat?.validStartLine ?? defaultConfigData.fdrValidStartLine
} else if (type === 'logManage') {
configFormData.delimiter = rightClickData.value.options?.plcFormat?.delimiter ?? defaultConfigData.plcDelimiter
configFormData.timeFormat = rightClickData.value.options?.plcFormat?.timeFormat ?? defaultConfigData.plcTimeFormat
configFormData.validStartLine = rightClickData.value.options?.plcFormat?.validStartLine ?? defaultConfigData.plcValidStartLine
}
}
const configFormRules = {
timeFormat: [
{
required: true,
message: '请输入时间格式',
trigger: 'blur',
},
],
delimiter: [
{
required: true,
message: '请输入分隔符',
trigger: 'blur',
},
],
validStartLine: [
{
required: true,
message: '请输入有效起始行',
trigger: 'change',
},
],
}
const submitConfig = () => {
configFormRef.value?.validate((valid) => {
if (valid) {
setAirBlowerConfig()
.then(() => {
ElMessage.success('配置成功')
configDialogVisible.value = false
})
.then(() => {
return getTreeDataList()
})
.then(() => {
nextTick(() => {
treeRef.value?.setCurrentKey(curTreeData.value.id, false)
curTreeData.value = treeRef.value?.getCurrentNode()
})
})
.catch((err) => {
ElMessage.error(err)
})
}
})
}
const cancelConfig = () => {
configDialogVisible.value = false
configFormRef.value?.resetFields()
}
const setAirBlowerConfig = () => {
return new Promise((resolve) => {
if (setConfigType.value === 'malFunction') {
const stringify = JSON.stringify({ fdrFormat: configFormData })
setConfigReq({
id: rightClickData.value.id,
options: stringify,
})
.then(() => {
resolve(true)
})
.catch(() => {
throw '配置失败'
})
} else if (setConfigType.value === 'logManage') {
const stringify = JSON.stringify({ plcFormat: configFormData })
setLogConfigReq({
id: rightClickData.value.id,
options: stringify,
})
.then(() => {
resolve(true)
})
.catch(() => {
throw '配置失败'
})
}
})
}
const fileName = ref('')
const warningInfo = ref()
const previewFileDialogVisible = ref(false)
const readFile = (data: tableItemData) => {
fileName.value = activeName.value === 'malFunction' ? data.name.slice(24) : data.name
previewFileDialogVisible.value = true
getFileKeyEnum().finally(() => {
getFileData(data.path)
.then((res: { data: any; faultTime?: any }) => {
previewChartData = res.data
const attrName = Object.keys(res.data)
const data: any = []
let hasAddFaultTime = false
attrName.forEach((item) => {
if (item === 'TimeStamp') {
let timeStamp: any = []
previewChartData.TimeStamp = previewChartData.TimeStamp.map((item: any) => {
const parseTime = dayjs(item).format('YYYY-MM-DD HH:mm:ss.SSS')
if (!hasAddFaultTime && res?.faultTime && item > res?.faultTime) {
const parseFaultTime = dayjs(res.faultTime).format('YYYY-MM-DD HH:mm:ss.SSS')
warningInfo.value = parseFaultTime
timeStamp.push(parseFaultTime)
hasAddFaultTime = true
}
timeStamp.push(parseTime)
return parseTime
})
warningChartData.TimeStamp = timeStamp
} else if (item === 'TimeStampUTC') {
previewChartData.TimeStamp = previewChartData.TimeStampUTC.map((item: any) => {
return dayjs(item).format('YYYY-MM-DD HH:mm:ss.SSS')
})
} else {
data.push({
label: fileKeyEnums?.[item] ?? item,
key: item,
isLeaf: true,
})
}
})
previewTreeData.value = data
originPreviewTreeData = data
})
.catch((err) => {
const info = err.response?.data?.msg
ElMessage.error(info || '文件读取失败')
})
.finally(() => {
previewTreeLoading.value = false
})
})
}
const downloadFile = (data: tableItemData) => {
runDownLoad(data)
.then((res) => {
const url = window.URL.createObjectURL(res.data)
const a = document.createElement('a')
a.style.display = 'none'
a.href = url
a.download = data.name
document.body.appendChild(a)
a.click()
window.URL.revokeObjectURL(url)
document.body.removeChild(a)
})
.catch((err) => {
ElMessage.error(err)
})
}
const runDownLoad = (data: tableItemData) => {
if (activeName.value === 'malFunction') {
return downloadFileReq({ url: data.path })
} else if (activeName.value === 'logManage') {
return downloadLogFileReq({ url: data.path })
}
return Promise.reject()
}
const closePreviewFileDialog = () => {
previewTreeData.value = []
previewChartData = []
selectPreviewTree = []
curSeries = []
previewChartInstance && previewChartInstance.clear()
}
const previewTreeLoading = ref(false)
const previewTreeRef = ref<TreeInstance>()
const previewTreeData = ref()
let originPreviewTreeData: any = []
const previewTreeProps = {
children: 'children',
label: 'label',
isLeaf: 'isLeaf',
}
const previewSearchTreeVal = ref('')
const previewSearchTree = (val: string) => {
nextTick(() => {
previewTreeRef.value?.setCheckedKeys(selectPreviewTree)
})
if (val === '') {
previewTreeData.value = originPreviewTreeData
return
}
const regex = new RegExp(val, 'i')
const filterData = originPreviewTreeData.filter((item: any) => regex.test(item.label))
previewTreeData.value = filterData
}
const clearPreviewTree = () => {
nextTick(() => {
selectPreviewTree = []
previewTreeRef.value?.setCheckedKeys(selectPreviewTree)
})
previewChartInstance && previewChartInstance.clear()
}
let selectPreviewTree: any = []
const handleCheckChange = (data: any, state: { checkedKeys: string[] }) => {
previewChartInstance && previewChartInstance.clear()
selectPreviewTree = state.checkedKeys
if (selectPreviewTree.length > 0) {
initPreviewChart()
} else {
previewChartInstance && previewChartInstance.clear()
}
}
// const previewNodeClick = (data: any) => {
// if (selectPreviewTree.includes(data.key)) {
// previewTreeRef.value?.setChecked(data.key, false, false)
// }else{
// previewTreeRef.value?.setChecked(data.key, true, false)
// }
// }
let previewChartData: any = {}
let warningChartData: any = {}
let curSeries: any = []
let previewChartInstance: any = null
const previewChartRef = ref()
const getRandomDarkColor = () => {
let r = Math.floor(Math.random() * 200) // 限制在0到127之间以生成较深的颜色
let g = Math.floor(Math.random() * 200)
let b = Math.floor(Math.random() * 200)
let color = `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`
return color
}
const createSeriresData = () => {
const seriesData: any = []
const curAttr = curSeries.map((item: any) => item.id)
selectPreviewTree.forEach((item: string) => {
if (curAttr.includes(item)) {
const seriesItem = curSeries.find((cur: any) => cur.id === item)
seriesData.push(seriesItem)
} else {
const color = getRandomDarkColor()
const createName = fileKeyEnums?.[item] ? fileKeyEnums[item] + (fileKeyUnit[item] ? `${fileKeyUnit[item] ?? ''}` : '') : item
const data = {
id: item,
name: createName,
type: 'line',
barWidth: 20,
itemStyle: {
color: color,
barBorderRadius: 2,
},
smooth: 0.6,
symbol: 'none',
xAxisIndex: 0,
data: previewChartData[item],
}
seriesData.push(data)
}
})
curSeries = seriesData
return seriesData
}
const initPreviewChart = () => {
const chart = previewChartInstance ?? echarts.init(previewChartRef.value)
const series = createSeriresData()
const option = {
grid: {
top: 50,
right: 23,
bottom: 50,
left: 18,
containLabel: true,
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'line',
},
},
xAxis: [
{
type: 'category',
axisLine: {
show: true,
lineStyle: {
color: '#dadada',
width: 1,
type: 'solid',
},
},
axisLabel: {
//x轴文字的配置
show: true,
color: '#4E5969',
interval: 'auto',
formatter: function (value: any) {
return value.slice(11)
},
//rotate: 45
},
splitLine: {
//分割线配置
show: false,
lineStyle: {
color: '#999999',
},
},
data: previewChartData['TimeStamp'],
},
{
type: 'category',
show: false,
data: warningChartData.TimeStamp,
},
],
yAxis: [
{
type: 'value',
name: '历史值',
nameTextStyle: {
color: '#4E5969',
},
axisLine: {
show: false,
lineStyle: {
color: '#dadada',
width: 0,
type: 'solid',
},
},
axisLabel: {
//x轴文字的配置
show: true,
color: '#4E5969',
},
axisTick: { show: false },
splitLine: {
interval: 50,
lineStyle: {
type: 'dashed',
color: '#dadada',
},
},
},
],
dataZoom: [
{
type: 'inside',
start: 0,
end: 100,
},
{
start: 0,
end: 100,
},
],
legend: {
data: [],
textStyle: {
color: '#73767a',
},
},
series:
activeName.value === 'malFunction'
? [
...series,
{
type: 'line',
name: '报警值',
data: [],
xAxisIndex: 1,
tooltip: {
show: false,
},
markLine: {
symbol: 'none',
data: [
{
xAxis: warningInfo.value,
},
],
animation: false,
},
},
]
: series,
}
chart.setOption(option)
previewChartInstance = chart
}
const getFileData = (url: string) => {
previewTreeLoading.value = true
if (activeName.value === 'malFunction') {
return previewFileReq({
deviceCode: curTreeData.value.code,
url: url,
}).then((res) => {
return { data: res.data.dataCurve, faultTime: res.data?.faultTime }
})
} else if (activeName.value === 'logManage') {
return previewLogFileReq({
deviceCode: curTreeData.value.code,
url: url,
}).then((res) => {
return { data: res.data }
})
}
return Promise.reject()
}
const fileKeyEnums: any = {}
const fileKeyUnit: any = {}
const getFileKeyEnum = () => {
return new Promise((resolve, reject) => {
if (activeName.value === 'malFunction') {
getFileKeyEnumsReq({
madeinfactory: curTreeData.value.madeinFactory,
model: curTreeData.value.model,
})
.then((res) => {
if (res.success) {
res.data.forEach((item: any) => {
fileKeyEnums[item.variable] = item?.description ?? item.variable
fileKeyUnit[item.variable] = item?.unit ?? ''
})
resolve(true)
}
})
.catch(() => {
reject(false)
})
} else if (activeName.value === 'logManage') {
getLogFileKeyEnumsReq({
madeinfactory: curTreeData.value.madeinFactory,
model: curTreeData.value.model,
})
.then((res) => {
if (res.success) {
res.data.forEach((item: any) => {
fileKeyEnums[item.variable] = item?.description ?? item.variable
fileKeyUnit[item.variable] = item?.unit ?? ''
})
resolve(true)
}
})
.catch(() => {
reject(false)
})
}
})
}
let logOriginTableData = ref<tableItemData[]>([])
const logTableData = computed(() => {
let data = logOriginTableData.value
if (searchData.fileName) {
const reg = new RegExp(searchData.fileName, 'i')
data = data.filter((item) => reg.test(item.name))
}
const res = data.slice((logPageSetting.current - 1) * logPageSetting.pageSize, logPageSetting.current * logPageSetting.pageSize)
logPageSetting.total = res.length
return res
})
const logPageSetting = reactive({
current: 1,
pageSize: 20,
total: 0,
pageSizes: [20, 50, 100],
})
const activeName = ref<'malFunction' | 'logManage'>('malFunction')
const checkTab = () => {
getListForAirBlower()
}
onMounted(() => {
getTreeDataList().then((data: any) => {
const queryId = route.query.deviceId ?? data.id
treeRef.value && treeRef.value.setCurrentKey(queryId, true)
curTreeData.value = treeRef.value?.getCurrentNode()
getListForAirBlower()
})
})
onUnmounted(() => {
previewChartInstance && previewChartInstance.dispose()
previewChartInstance = null
})
</script>
<style lang="scss" scoped>
.malfunction {
width: 100%;
height: 100%;
.container {
width: 100%;
height: 100%;
.aside {
width: 260px;
height: 100%;
padding: 0 20px;
border-right: 1px solid #eaebed;
.searchTree {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 80px;
.el-input {
width: 220px;
height: 40px;
}
}
.treeMain {
width: 100%;
height: calc(100% - 80px);
}
}
.mainContainer {
width: calc(100% - 260px);
height: 100%;
.header {
display: flex;
align-items: center;
width: 100%;
height: 80px;
.searchFileName {
display: flex;
align-items: center;
width: 320px;
height: 40px;
span {
width: 70px;
}
.el-input {
width: 220px;
height: 40px;
}
}
.searchDate {
display: flex;
align-items: center;
width: 400px;
height: 40px;
span {
flex-shrink: 0;
width: 45px;
}
:deep(.el-date-editor) {
width: 400px;
height: 40px;
}
}
.btnPart {
margin-left: auto;
width: 360px;
text-align: right;
.el-button {
margin: 0 10px;
width: 100px;
height: 40px;
}
}
}
.main {
width: 100%;
height: calc(100% - 80px);
.tabs {
width: 100%;
height: 100%;
:deep(.el-tabs__content) {
width: 100%;
height: calc(100% - 60px);
.tabPane {
width: 100%;
height: 100%;
}
}
.tableMain {
width: 100%;
height: calc(100% - 32px);
.tableClass {
width: 100%;
height: 100%;
.tableBtnPart {
display: flex;
justify-content: center;
.el-button {
margin: 0;
}
}
}
}
.footerPart {
display: flex;
justify-content: right;
}
}
}
}
}
}
.el-input-number {
width: 100%;
}
.previewFilePart {
width: 100%;
height: 500px;
.colPart {
width: 100%;
height: 100%;
.title {
padding-left: 20px;
width: 100%;
height: 30px;
font-size: 20px;
}
.previewTreeScrollbar {
height: calc(100% - 40px);
}
.chartPart {
position: relative;
width: 100%;
height: calc(100% - 40px);
.label {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100px;
font-size: 20px;
}
.previewChart {
width: 100%;
height: 100%;
}
}
}
.leftCol {
border-right: 1px solid #eaebed;
.search {
display: flex;
}
.previewSearchTree {
width: calc(100% - 80px);
height: 40px;
padding: 0 10px 10px 20px;
}
.el-button {
margin: 0 10px 10px 0;
width: 70px;
height: 30px;
}
}
}
.contextMenuBtns {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
height: 90px;
.el-button {
margin: 0;
height: 40px;
}
}
</style>