提交更改版本

This commit is contained in:
zhujiyan
2024-07-22 10:35:01 +08:00
parent 33a41b9d7a
commit bccf61c6d1
31 changed files with 180231 additions and 443 deletions

View File

@@ -8,6 +8,40 @@
<PointTree @node-click="nodeClick" @init="nodeClick"></PointTree>
<div class="device-control-right" v-if="deviceData">
<el-descriptions title="设备基本信息" class="mb10" :column="3" border>
<template #extra>
<el-button
v-if="dataSet.indexOf('_realtimedata') != -1"
size="small"
type="primary"
@click="handleDownLoad"
>
模版下载
</el-button>
<el-button
v-if="dataSet.indexOf('_realtimedata') != -1"
size="small"
type="primary"
@click="handleImport"
>
离线数据导入
</el-button>
<el-button
v-if="dataSet.indexOf('_realtimedata') != -1"
size="small"
type="primary"
@click="handleaddDevice"
>
设备补招
</el-button>
<el-button
v-if="dataSet.indexOf('_realtimedata') != -1"
size="small"
type="primary"
@click="handleImport"
>
解析列表
</el-button>
</template>
<el-descriptions-item label="名称">
{{ deviceData.name ? deviceData.name : '/' }}
</el-descriptions-item>
@@ -166,8 +200,28 @@
</div>
<!-- 实时数据 -->
<div style="height: calc(100vh - 200px)" v-if="dataSet.indexOf('_realtimedata') != -1">
实时数据
<RealTime></RealTime>
<div class="view_top_btn" v-if="realTimeFlag">
<el-button type="primary" size="small" :icon="Platform" @click="handleRecordWaves">
实时录波
</el-button>
<el-button type="primary" size="small" :icon="TrendCharts" @click="handleTrend">
实时趋势
</el-button>
<el-button type="primary" size="small" :icon="DataLine" @click="handleHarmonicSpectrum">
谐波频谱
</el-button>
</div>
<div class="view_top_btn" v-if="!realTimeFlag">
<el-button type="primary" :icon="ArrowLeft" size="small" @click="handleReturn">返回</el-button>
</div>
<!-- 实时数据主界面组件 -->
<realTime v-if="realTimeFlag" ref="realTimeRef"></realTime>
<!-- 实时数据-实时录波组件 -->
<recordWoves v-if="!realTimeFlag && sonTab == 0"></recordWoves>
<!-- 实时数据-实时趋势组件 -->
<realTrend v-if="!realTimeFlag && sonTab == 1"></realTrend>
<!-- 实时数据-谐波频谱组件 -->
<harmonicSpectrum v-if="!realTimeFlag && sonTab == 2"></harmonicSpectrum>
</div>
<!-- 暂态事件 -->
<div style="height: calc(100vh - 200px)" v-if="dataSet.indexOf('_event') != -1">
@@ -175,19 +229,12 @@
<Event></Event>
</div>
<div v-if="!tableData" style="height: 42px"></div>
<!-- <el-tab-pane lazy label="趋势数据" name="0">
<div style="height:calc(100vh - 330px);overflow: auto;border:1px solid red;"></div>
</el-tab-pane>
<el-tab-pane lazy label="实时数据" name="1">
<div style="height:calc(100vh - 330px);overflow: auto;border:1px solid red;"></div>
</el-tab-pane>
<el-tab-pane lazy label="暂态事件" name="2">
<div style="height:calc(100vh - 330px);overflow: auto;border:1px solid red;"></div>
</el-tab-pane> -->
</el-tabs>
</div>
<el-empty v-else description="请选择设备" class="device-control-right" />
<Detail ref="detailRef" :detail="detail" @close="detail = null" v-if="detail"></Detail>
<!-- 离线数据导入组件 -->
<offLineDataImport ref="offLineDataImportRef"></offLineDataImport>
</div>
</template>
@@ -196,17 +243,22 @@ import Detail from './detail.vue'
import PointTree from '@/components/tree/govern/pointTree.vue'
import { mainHeight } from '@/utils/layout'
import { queryByCode, queryByid, queryCsDictTree } from '@/api/system-boot/dictTree'
import { getDeviceData } from '@/api/cs-device-boot/EquipmentDelivery'
import { deviceHisData, deviceRtData } from '@/api/cs-device-boot/csGroup'
import { getGroup } from '@/api/cs-device-boot/csGroup'
import { ref, reactive, nextTick, onMounted } from 'vue'
import { getDeviceData, getTabsDataByType } from '@/api/cs-device-boot/EquipmentDelivery'
import { deviceHisData, deviceRtData, getGroup } from '@/api/cs-device-boot/csGroup'
import { ref, reactive, nextTick, onMounted, watch } from 'vue'
import { ElMessage } from 'element-plus'
import DatePicker from '@/components/form/datePicker/index.vue'
import Trend from './tabs/trend.vue'
import RealTime from './tabs/realtime.vue'
import Trend from './tabs/trend.vue' //趋势数据
import realTime from './tabs/realtime.vue' //实时数据-主界面
import realTrend from './tabs/components/realtrend.vue' //实时数据-实时趋势
import harmonicSpectrum from './tabs/components/harmonicSpectrum.vue' //实时数据-谐波频谱子页面
import recordWoves from './tabs/components/recordwoves.vue' //实时数据-实时录波子页面
import offLineDataImport from './offLineDataImport/index.vue'
import Event from './tabs/event.vue'
import { useRouter } from 'vue-router'
import { defineConfig, loadEnv } from 'vite'
import type { UserConfig, ConfigEnv } from 'vite'
import { Platform, TrendCharts, DataLine, ArrowLeft } from '@element-plus/icons-vue'
defineOptions({
name: 'govern/device/control'
})
@@ -238,6 +290,7 @@ const socket: any = ref(null)
const url = 'wss://your-websocket-url'
//连接websocket
const connectWebSocket = () => {
return
socket.value = new WebSocket(url)
socket.value.onopen = () => {
console.log('WebSocket connected')
@@ -269,7 +322,30 @@ const disconnectWebSocket = () => {
socket.value.close()
}
}
//是否显示实时数据默认内容
const realTimeFlag = ref(true)
//实时数据子菜单
const sonTab = ref()
//实时录波
const handleRecordWaves = () => {
realTimeFlag.value = false
sonTab.value = 0
}
//实时趋势
const handleTrend = () => {
realTimeFlag.value = false
sonTab.value = 1
}
//谐波频谱
const handleHarmonicSpectrum = () => {
realTimeFlag.value = false
sonTab.value = 2
}
//返回
const handleReturn = () => {
realTimeFlag.value = true
sonTab.value = null
}
const getDeviceDataTrend = (e: any) => {
detail.value = {
lineId: formInline.lineId,
@@ -285,18 +361,30 @@ const handleSizeChange = (val: number) => {
formInline.pageSize = val
handleClick()
}
const { push, options, currentRoute } = useRouter()
//设备补招
const handleaddDevice = () => {
push({
path: '/supplementaryRecruitment',
query: {
id: '1111'
}
})
}
//树节点点击事件
const deviceId: any = ref('')
const lineId: any = ref('')
const nodeClick = async (e: anyObj) => {
deviceId.value = e.pid
lineId.value = e.id
if (!e) {
loading.value = false
return
}
console.log(e, '监测点请求的判断')
if (e.level == 3) {
loading.value = true
formInline.lineId = e.id
await getDeviceData(e.pid, 'history', e.id).then((res: any) => {
console.log(res.data, '-------------')
deviceData.value = res.data
if (!res.data.dataSetList) {
dataSet.value = ''
@@ -330,40 +418,89 @@ const nodeClick = async (e: anyObj) => {
loading.value = false
}
}
const realTimeRef: any = ref()
const intRealTime = (val: any) => {
getTabsDataByType(val).then(res => {
realTimeRef.value && realTimeRef.value.getRealTimeData(res.data)
})
}
//tab点击事件
const handleClick = async (tab?: any) => {
tableLoading.value = true
//初始化点击tab隐藏实时录波、实时趋势、谐波频谱按钮
realTimeFlag.value = false
//初始化点击tab隐藏子页面
sonTab.value = null
if (tab) {
tableData.value = []
formInline.pageNum = 1
}
// setTimeout(() => {
//查询历史模块数据
// setTimeout(async () => {
//查询历史指标
if (dataSet.value.indexOf('_history') != -1) {
console.log('_history')
formInline.startTime = datePickerRef.value.timeValue[0]
formInline.endTime = datePickerRef.value.timeValue[1]
formInline.id = dataSet.value.replace('_history', '')
await deviceHisData(formInline).then((res: any) => {
console.log(res)
tableData.value = res.data.records
formInline.total = res.data.total
tableLoading.value = false
})
}
//查询数据趋势数据
console.log(dataSet.value.indexOf('_trenddata'), '-------')
//查询趋势数据
if (dataSet.value.indexOf('_trenddata') != -1) {
console.log(deviceData.value.dataSetList, '8888888888838838838')
console.log('_trenddata')
let obj = {
devId: deviceId.value, //e.id
lineId: lineId.value, //e.pid
type: 1,
list: [
{
lineId: lineId.value,
devId: dataSet.value.replace('_trenddata', '')
}
]
}
await getTabsDataByType(obj).then(res => {
console.log(res, '0000000')
})
}
//查询实时数据
if (dataSet.value.indexOf('_realtimedata') != -1) {
console.log('_realtimedata')
//查询实时数据显示实时录波、实时趋势、谐波频谱
realTimeFlag.value = true
let obj = {
type: 2,
devId: deviceId.value, //e.id
lineId: lineId.value //e.pid
}
intRealTime(obj)
await setTimeout(() => {
intRealTime(obj)
}, 20000)
}
//查询暂态事件
if (dataSet.value.indexOf('_event') != -1) {
console.log('_event')
} else {
let obj = {
devId: deviceId.value, //e.id
lineId: lineId.value, //e.pid
type: 3,
list: [
{
lineId: lineId.value,
devId: dataSet.value.replace('_event', '')
}
]
}
await getTabsDataByType(obj).then(res => {
console.log(res, '0000000')
})
}
//查询当前指标
console.log(dataSet.value.indexOf('_'), '查询当前指标')
if (dataSet.value.indexOf('_') == -1) {
formInline.id = dataSet.value
await deviceRtData(formInline).then((res: any) => {
tableData.value = res.data.records
@@ -373,6 +510,12 @@ const handleClick = async (tab?: any) => {
}
// }, 100)
}
//离线数据导入
const offLineDataImportRef = ref()
const handleImport = () => {
offLineDataImportRef.value && offLineDataImportRef.value.open()
}
queryByCode('Device_Type').then(res => {
queryCsDictTree(res.data.id).then(res => {
devTypeOptions.value = res.data.map((item: any) => {
@@ -421,6 +564,14 @@ const openGroup = () => {
})
})
}
watch(
() => dataSet.value,
(val: any, oldVal: any) => {
if (val) {
handleClick()
}
}
)
onMounted(() => {
connectWebSocket()
})
@@ -486,4 +637,12 @@ onMounted(() => {
}
}
}
.view_top_btn {
width: 100%;
height: 40px;
display: flex;
align-items: center;
justify-content: flex-end;
}
</style>

View File

@@ -0,0 +1,231 @@
<!-- 离线数据导入 -->
<template>
<el-dialog v-model="dialogVisible" title="文件列表" width="60%" draggable>
<!-- 上传文件列表 -->
<div class="offline_data">
<div class="offline_data_btn">
<el-button type="primary">开始上传</el-button>
<el-button type="primary">清空文件</el-button>
</div>
<div class="offline_data_list">
<!-- <el-upload
ref="upload"
accept=".zip,.rar,.7z"
action="#"
:auto-upload="false"
:on-change="handleFileChange"
> -->
<!-- <el-button slot="trigger" size="small" type="primary">选择ZIP文件</el-button> -->
<el-button
:loading="loading"
style="margin-left: 10px"
size="small"
type="primary"
@click="submitUpload"
>
上传离线数据
</el-button>
<!-- </el-upload> -->
<div v-if="zipFiles.length">
<el-table :data="zipFiles" style="width: 100%" height="280">
<el-table-column prop="name" label="文件名" align="left"></el-table-column>
<el-table-column prop="status" label="状态" align="left"></el-table-column>
<el-table-column label="操作" width="100" fixed="right" align="center">
<template #default="{ row }">
<!-- <el-button size="small" @click="previewFile(row)">预览</el-button> -->
<el-button size="small" type="danger" text @click="removeFile(row)">移除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="close">取消</el-button>
<!-- <el-button type="primary" @click="close">提交</el-button> -->
</div>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import JSZip from 'jszip'
import { saveAs } from 'file-saver'
import { ElMessageBox } from 'element-plus'
const dialogVisible = ref(false)
const selectedFile = ref(null)
const loading = ref(false)
const zipFiles: any = ref([])
//上传zip
const handleFileChange = (file: any, fileList: any) => {
console.log(fileList, 'fileList555333222')
loading.value = true
JSZip.loadAsync(file.raw)
.then(zip => {
console.log(file.raw, '++++++++++++hahhahahabvggeiwtei哈哈')
zipFiles.value = Object.keys(zip.files).map(name => ({ name }))
// Object.keys(zip.files).map(entry => {
// console.log(entry, 'entryentryentryentryentry')
// // return zips.file(entry).then((blob: any) => {
// // 创建File对象
// return new File(['file'], entry)
// // })
// })
// console.log(zip.files, 'zip.fileszip.fileszip.fileszip.files')
})
.catch(error => {
console.error('解压错误:', error)
ElMessageBox.alert('解压错误: ' + error.message, '错误', { type: 'error' })
})
.finally(() => {
loading.value = false
})
const reader = new FileReader()
const zip = new JSZip()
reader.onload = e => {
console.log(e, '++++++++++++EEeeeEEEEEEEEE')
// 加载压缩包内容
zip.loadAsync(e.target.result).then(zip => {
console.log(e.target.result, '??????????')
// 获取压缩包内的文件
const files = Object.values(zipFiles.value)
.map((entry: any) => {
if (!entry.dir && entry.name) {
// 将压缩包内的文件转换为Blob对象
return zip
.file(entry.name)
.async('blob')
.then(blob => {
// 创建File对象
return new File([blob], entry.name)
})
}
})
.filter(Boolean) // 过滤掉文件夹和未定义的文件
Promise.all(files).then(allFiles => {
// 这里你已经拿到了压缩包内所有文件的File对象数组
console.log(allFiles)
})
})
}
// 读取文件内容
reader.readAsArrayBuffer(file.raw)
}
const uploadChange = e => {
const formData = new FormData()
const file = e.target['files']
for (let i = 0; i < file.length; i++) {
formData.append('files', file[i])
console.log(file[i])
console.log(file[i].webkitRelativePath)
}
console.log(formData.getAll('files'), '++++++++++++++++')
}
const upload = ref()
const submitUpload = e => {
e.preventDefault()
// upload.value.submit()
const input = document.createElement('input')
// input["style"] = "background: rgba(255, 255, 255, 0);overflow: hidden;position: fixed;width: 1px;height: 1px;z-index: -1;opacity: 0;";
input.type = 'file'
input.setAttribute('allowdirs', 'true')
input.setAttribute('directory', 'true')
input.setAttribute('webkitdirectory', 'true')
input.multiple = true
document.querySelector('body').appendChild(input)
// todo 这里增加了input标签可以给它删掉
input.click()
// 覆盖原生的 alert 函数
// window.alert = function (message) {
// console.log(message) // 可以在这里处理消息或者什么都不做
// }
// // 覆盖原生的 confirm 函数
// window.confirm = function (message) {
// console.log(message) // 可以在这里处理消息或者返回 true 或 false
// return false // 始终返回 false 来模拟用户点击“取消”
// }
// // 覆盖原生的 prompt 函数
// window.prompt = function (message, defaultValue) {
// console.log(message, defaultValue) // 可以在这里处理消息和默认值
// return null // 始终返回 null 来模拟用户点击“取消”
// }
input.onclick = e => {
e.preventDefault()
}
input.onchange = async function (e) {
const formData = new FormData()
e.preventDefault()
const file = e.target['files']
for (let i = 0; i < file.length; i++) {
formData.append('files', file[i])
console.log(file[i])
console.log(file[i].webkitRelativePath)
}
console.log(formData.getAll('files'), '++++++++++++++++')
}
}
const previewFile = (file: any) => {
// 这里可以实现文件预览逻辑,例如图片预览等
console.log('预览文件:', file.name)
}
//移除文件
const removeFile = async (file: any) => {
console.log(file, '移除文件指令')
const zip = new JSZip()
// 假设有一个zip文件的ArrayBuffer数据
const zipBuffer = file
// 加载ZIP文件
// const jszip = await zip.loadAsync(zipBuffer)
// 删除指定文件
// delete jszip.files[file.name]
// 生成新的ZIP文件
const newZipContent = await zip.generateAsync({ type: 'arraybuffer', platform: 'DOS' })
// 处理新生成的ZIP文件例如下载或者其他操作
// ...
// 使用FileSaver库保存新的ZIP文件
saveAs(newZipContent, '5555.zip')
}
const open = () => {
dialogVisible.value = true
}
const close = () => {
dialogVisible.value = false
}
onMounted(() => {
console.log()
})
defineExpose({ open })
</script>
<style lang="scss" scoped>
.offline_data {
width: 100%;
height: 400px;
border: 2px solid red;
.offline_data_btn {
width: 100%;
height: 40px;
display: flex;
align-items: center;
justify-content: flex-end;
}
.offline_data_list {
width: 100%;
height: 300px;
}
}
</style>

View File

@@ -0,0 +1,23 @@
<template>
<div class="default-main">
<el-tabs v-model="activeName" type="border-card">
<el-tab-pane label="当前设备补招" name="0">
<current v-if="activeName == '0'" />
</el-tab-pane>
<el-tab-pane label="历史设备补招" name="1">
<history v-if="activeName == '1'" />
</el-tab-pane>
</el-tabs>
</div>
</template>
<script lang='ts' setup>
import {ref,onMounted} from 'vue';
import current from './supplementaryRecruitment/current.vue'
import history from './supplementaryRecruitment/history.vue'
const activeName=ref('0')
onMounted(()=>{
console.log()
})
</script>
<style lang='scss' scoped>
</style>

View File

@@ -0,0 +1,606 @@
<!-- 当前设备补招 -->
<template>
<div class="default-main">
<TableHeader>
<template v-slot:select>
<el-form-item label="设备类型">
<!-- <el-input v-model="tableStore.table.params.searchValue" placeholder="请输入设备类型" /> -->
<el-select
v-model="tableStore.table.params.devType"
clearable
@change="devTypeChange"
placeholder="请选择设备类型"
>
<el-option
v-for="item in devTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="设备型号">
<el-select v-model="tableStore.table.params.devModel" clearable placeholder="请选择设备型号">
<el-option
v-for="item in devModelOptionsFilter"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="通讯协议">
<el-select v-model="tableStore.table.params.devAccessMethod" clearable placeholder="请选择通讯协议">
<el-option label="MQTT" value="mqtt"></el-option>
<el-option label="CLD" value="cloud"></el-option>
</el-select>
</el-form-item>
<el-form-item label="状态">
<el-select v-model="tableStore.table.params.status" clearable placeholder="请选择状态">
<el-option label="未注册" :value="1"></el-option>
<el-option label="注册" :value="2"></el-option>
<el-option label="接入" :value="3"></el-option>
</el-select>
</el-form-item>
</template>
<template v-slot:operation>
<el-button type="primary" @click="downLoadFile" class="ml10" icon="el-icon-Download">
模版下载
</el-button>
<el-upload
style="display: inline-block"
action=""
accept=".xlsx"
class="upload-demo"
:show-file-list="false"
:auto-upload="false"
:on-change="bulkImport"
>
<el-button type="primary" class="ml10" icon="el-icon-Tickets">批量导入</el-button>
</el-upload>
<el-button type="primary" class="ml10" @click="add" icon="el-icon-Plus">新增设备</el-button>
</template>
</TableHeader>
<Table ref="tableRef"></Table>
<el-dialog
:title="dialogTitle"
v-model="dialogFormVisible"
:close-on-click-modal="false"
:before-close="resetForm"
draggable
width="40%"
>
<el-form :model="form" label-width="120px" :rules="rules" ref="ruleFormRef">
<el-form-item label="设备名称:" prop="name">
<el-input
v-model="form.name"
autocomplete="off"
clearable
placeholder="请输入(项目名称+设备名称)"
></el-input>
</el-form-item>
<el-form-item label="网络设备ID:" prop="ndid" class="top">
<el-input v-model="form.ndid" autocomplete="off" placeholder="请输入"></el-input>
</el-form-item>
<el-form-item label="设备类型:" prop="devType" class="top">
<el-select v-model="form.devType" placeholder="请选择" @change="formDevTypeChange" clearable>
<el-option
v-for="item in devTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="设备型号:" prop="devModel" class="top">
<el-select v-model="form.devModel" placeholder="请选择" clearable>
<el-option
v-for="item in formDevModelOptionsFilter"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="通讯协议:" prop="devAccessMethod" class="top">
<el-select v-model="form.devAccessMethod" placeholder="请选择" clearable>
<el-option label="MQTT" value="MQTT"></el-option>
<el-option label="CLD" value="cloud"></el-option>
</el-select>
</el-form-item>
<el-form-item label="合同号:" prop="cntractNo" class="top">
<el-input v-model="form.cntractNo" autocomplete="off" placeholder="请输入"></el-input>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="resetForm"> </el-button>
<el-button type="primary" @click="onSubmit"> </el-button>
</template>
</el-dialog>
<div class="qrcode-label">
<div class="qrcode-label-title">{{ deivce.mac }}</div>
<img class="qrcode-label-img" alt="二维码加载失败" :src="deivce.qrPath" />
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, provide, computed, reactive, nextTick } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import { queryByCode, queryByid, queryCsDictTree } from '@/api/system-boot/dictTree'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
addEquipmentDelivery,
deleteEquipmentDelivery,
editEquipmentDelivery,
batchImportDevice,
resetEquipmentDelivery,
governDeviceRegister,
portableDeviceRegister,
portableDeviceAccess
} from '@/api/cs-system-boot/device'
import html2canvas from 'html2canvas'
import { fullUrl } from '@/utils/common'
defineOptions({
name: 'govern/log/debug'
})
const devTypeOptions: any = ref([])
const deivce: any = ref({})
const ruleFormRef = ref()
const form = reactive({
cntractNo: '',
devAccessMethod: 'mqtt',
devModel: '',
devType: '',
name: '',
ndid: ''
})
const rules = reactive({
name: [{ required: true, message: '设备名不能为空', trigger: 'blur' }],
ndid: [{ required: true, message: '网络设备id不能为空', trigger: 'blur' }],
devType: [{ required: true, message: '设备类型不能为空', trigger: 'change' }],
devModel: [{ required: true, message: '设备型号不能为空', trigger: 'change' }],
devAccessMethod: [{ required: true, message: '接入方式不能为空', trigger: 'blur' }],
cntractNo: [{ required: true, message: '合同号不能为空', trigger: 'blur' }]
})
const dialogFormVisible = ref(false)
const dialogTitle = ref('新增设备')
const devModelOptions: any = ref([])
queryByCode('Device_Type').then(res => {
queryCsDictTree(res.data.id).then(res => {
devTypeOptions.value = res.data.map((item: any) => {
return {
value: item.id,
label: item.name,
...item
}
})
})
queryByid(res.data.id).then(res => {
devModelOptions.value = res.data.map((item: any) => {
return {
value: item.id,
label: item.name,
...item
}
})
})
tableStore.index()
})
const devModelOptionsFilter = computed(() => {
return devModelOptions.value.filter((item: any) => {
if (tableStore.table.params.devType) {
return item.pid == tableStore.table.params.devType
} else {
return true
}
})
})
const formDevModelOptionsFilter = computed(() => {
return devModelOptions.value.filter((item: any) => {
if (form.devType) {
return item.pid == form.devType
} else {
return true
}
})
})
const tableStore = new TableStore({
url: '/cs-device-boot/EquipmentDelivery/list',
method: 'POST',
column: [
{ title: '序号', type: 'seq',width:60 },
{ title: '设备名称', field: 'name' },
{
title: '设备类型',
field: 'devType',
formatter: row => {
return devTypeOptions.value.filter((item: any) => item.value == row.cellValue)[0]?.label
}
},
{
title: '设备型号',
field: 'devModel',
formatter: row => {
return devModelOptions.value.filter((item: any) => item.value == row.cellValue)[0]?.label
}
},
{
title: '通讯协议',
field: 'devAccessMethod',
formatter: row => {
return row.cellValue === 'MQTT' ? 'MQTT' : row.cellValue === 'cloud' ? 'CLD' : row.cellValue
}
},
{ title: '录入时间', field: 'createTime' },
{ title: '网络设备ID', field: 'ndid' },
{
title: '状态',
field: 'status',
width: 100,
render: 'tag',
custom: {
1: 'warning',
2: 'success',
3: 'primary',
4: 'primary',
5: 'warning'
},
replaceValue: {
1: '未注册',
2: '注册',
3: '接入',
4: '已取消',
5: '未接入'
}
// formatter: row => {
// return row.cellValue == 1 ? '未注册' : row.cellValue == 2 ? '注册' : '接入'
// },
},
{
title: '操作',
align: 'center',
width: '180',
render: 'buttons',
buttons: [
//直连装置注册
{
title: '注册',
type: 'primary',
icon: 'el-icon-Grid',
render: 'basicButton',
disabled: row => {
return (
(row.devType == '8b45cf6b7f5266e777d07c166ad5fa77' &&
row.devModel == 'a0d4da4b5c17b2172362a3f5a27bf217') ||
row.status != '1'
)
},
click: row => {
// 直连设备注册
ElMessageBox.confirm('确定注册该设备吗?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
governDeviceRegister({
nDid: row.ndid,
type: '4'
}).then(res => {
ElMessage.success(res.message)
tableStore.onTableAction('search', {})
})
})
.catch(e => {})
}
},
//便携式设备注册
{
title: '注册',
type: 'primary',
icon: 'el-icon-Grid',
render: 'basicButton',
disabled: row => {
// return (
// (row.devType != '8b45cf6b7f5266e777d07c166ad5fa77' &&
// row.devModel != 'a0d4da4b5c17b2172362a3f5a27bf217') ||
// row.status != '1'
// )
return true
},
click: row => {
// 便携式设备注册
ElMessageBox.confirm('确定注册该设备吗?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
portableDeviceRegister({
nDid: row.ndid
}).then(res => {
console.log(res, '8888')
ElMessage.success(res.message)
tableStore.index()
})
})
.catch(e => {})
}
},
//直连设备接入
{
title: '接入',
type: 'primary',
icon: 'el-icon-Grid',
render: 'basicButton',
disabled: row => {
return (
(row.devType == '8b45cf6b7f5266e777d07c166ad5fa77' &&
row.devModel == 'a0d4da4b5c17b2172362a3f5a27bf217') ||
row.status != '2'
)
},
click: row => {
// 直连设备接入
ElMessageBox.confirm('确定接入该设备吗?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
governDeviceRegister({
nDid: row.ndid,
type: '4'
}).then(res => {
ElMessage.success(res.message)
tableStore.onTableAction('search', {})
})
})
.catch(e => {})
}
},
//便携式设备接入
{
title: '接入',
type: 'primary',
icon: 'el-icon-Grid',
render: 'basicButton',
disabled: row => {
return (
(row.devType != '8b45cf6b7f5266e777d07c166ad5fa77' &&
row.devModel != 'a0d4da4b5c17b2172362a3f5a27bf217') ||
row.status == '3'
)
},
click: row => {
// 便携式设备接入
ElMessageBox.confirm('确定接入该设备吗?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
portableDeviceAccess({
nDid: row.ndid
}).then(res => {
ElMessage.success(res.message)
tableStore.index()
})
})
.catch(e => {})
}
},
{
title: '二维码',
type: 'primary',
icon: 'el-icon-Grid',
render: 'basicButton',
disabled: row => {
return (
row.devType == '8b45cf6b7f5266e777d07c166ad5fa77' &&
row.devModel == 'a0d4da4b5c17b2172362a3f5a27bf217'
)
},
click: row => {
deivce.value = row
deivce.value.qrPath = fullUrl(deivce.value.qrPath)
setTimeout(() => {
html2canvas(document.querySelector('.qrcode-label'), {
useCORS: true
}).then(canvas => {
let url = canvas.toDataURL('image/png')
// 下载图片
let a = document.createElement('a')
let event = new MouseEvent('click')
a.href = url
a.download = row.mac + '.png'
a.dispatchEvent(event)
})
}, 0)
}
},
{
name: 'edit',
title: '编辑',
type: 'primary',
icon: 'el-icon-EditPen',
render: 'basicButton',
click: async row => {
dialogFormVisible.value = true
dialogTitle.value = '编辑设备'
for (let key in form) {
form[key] = row[key]
}
form.id = row.id
}
},
{
name: 'del',
title: '删除',
type: 'danger',
icon: 'el-icon-Delete',
render: 'basicButton',
click: row => {
ElMessageBox.confirm('确定删除该设备吗?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
deleteEquipmentDelivery(row.id).then(res => {
ElMessage.success('删除成功!')
tableStore.onTableAction('search', {})
})
})
.catch(e => {})
}
}
]
}
],
beforeSearchFun: () => {
for (let key in tableStore.table.params) {
if (tableStore.table.params[key] === '') {
delete tableStore.table.params[key]
}
}
}
})
tableStore.table.params.orderBy = 'desc'
// 设备类型
const devTypeChange = (e: any) => {
if (!e) {
return
}
tableStore.table.params.devModel = ''
}
// 下载模版
const downLoadFile = () => {
window.open(window.location.origin + '/api/cs-device-boot/EquipmentDelivery/getExcelTemplate')
}
// 导入模版
const bulkImport = (e: any) => {
batchImportDevice(e.raw).then((res: any) => {
if (res.type === 'application/json') {
const reader = new FileReader()
reader.readAsText(res)
reader.onload = (e: any) => {
let data = JSON.parse(e.target.result)
if (data.code === 'A0000') {
ElMessage.success(data.message)
tableStore.onTableAction('search', {})
} else {
ElMessage.error(data.message)
}
}
} else {
ElMessage.error('导入失败!')
let url = window.URL.createObjectURL(res)
let link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', '导入失败.xlsx')
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
})
}
// 新增
const add = () => {
dialogFormVisible.value = true
dialogTitle.value = '新增设备'
}
// 确认
const onSubmit = () => {
ruleFormRef.value.validate((valid: any) => {
if (valid) {
if (dialogTitle.value == '新增设备') {
addEquipmentDelivery(form).then(res => {
ElMessage.success('新增成功')
resetForm()
tableStore.onTableAction('search', {})
})
} else {
editEquipmentDelivery(form).then(res => {
ElMessage.success('修改成功')
resetForm()
tableStore.onTableAction('search', {})
})
}
}
})
}
// 清空表格
const resetForm = () => {
ruleFormRef.value.resetFields()
dialogFormVisible.value = false
nextTick(() => {
// 模拟待编辑数据
let user = {
cntractNo: '',
devAccessMethod: 'mqtt',
devModel: '',
devType: '',
name: '',
ndid: ''
}
Object.assign(form, user)
})
}
const formDevTypeChange = (e: any) => {
if (!e) {
return
}
form.devModel = ''
}
provide('tableStore', tableStore)
onMounted(() => {
setTimeout(() => {
// tableStore.index()
}, 100)
})
const addMenu = () => {}
</script>
<style lang="scss" scoped>
.qrcode-label {
position: absolute;
top: 0;
right: 0;
z-index: -99;
display: flex;
align-items: center;
justify-content: center;
width: 180px;
height: 180px;
padding: 10px;
background: #fff;
flex-direction: column;
.qrcode-label-title {
margin-bottom: 10px;
font-size: 14px;
font-weight: bold;
}
.qrcode-label-img {
width: 140px;
height: 140px;
}
}
</style>

View File

@@ -0,0 +1,606 @@
<!-- 历史数据补招 -->
<template>
<div class="default-main">
<TableHeader>
<template v-slot:select>
<el-form-item label="设备类型">
<!-- <el-input v-model="tableStore.table.params.searchValue" placeholder="请输入设备类型" /> -->
<el-select
v-model="tableStore.table.params.devType"
clearable
@change="devTypeChange"
placeholder="请选择设备类型"
>
<el-option
v-for="item in devTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="设备型号">
<el-select v-model="tableStore.table.params.devModel" clearable placeholder="请选择设备型号">
<el-option
v-for="item in devModelOptionsFilter"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="通讯协议">
<el-select v-model="tableStore.table.params.devAccessMethod" clearable placeholder="请选择通讯协议">
<el-option label="MQTT" value="mqtt"></el-option>
<el-option label="CLD" value="cloud"></el-option>
</el-select>
</el-form-item>
<el-form-item label="状态">
<el-select v-model="tableStore.table.params.status" clearable placeholder="请选择状态">
<el-option label="未注册" :value="1"></el-option>
<el-option label="注册" :value="2"></el-option>
<el-option label="接入" :value="3"></el-option>
</el-select>
</el-form-item>
</template>
<template v-slot:operation>
<el-button type="primary" @click="downLoadFile" class="ml10" icon="el-icon-Download">
模版下载
</el-button>
<el-upload
style="display: inline-block"
action=""
accept=".xlsx"
class="upload-demo"
:show-file-list="false"
:auto-upload="false"
:on-change="bulkImport"
>
<el-button type="primary" class="ml10" icon="el-icon-Tickets">批量导入</el-button>
</el-upload>
<el-button type="primary" class="ml10" @click="add" icon="el-icon-Plus">新增设备</el-button>
</template>
</TableHeader>
<Table ref="tableRef"></Table>
<el-dialog
:title="dialogTitle"
v-model="dialogFormVisible"
:close-on-click-modal="false"
:before-close="resetForm"
draggable
width="40%"
>
<el-form :model="form" label-width="120px" :rules="rules" ref="ruleFormRef">
<el-form-item label="设备名称:" prop="name">
<el-input
v-model="form.name"
autocomplete="off"
clearable
placeholder="请输入(项目名称+设备名称)"
></el-input>
</el-form-item>
<el-form-item label="网络设备ID:" prop="ndid" class="top">
<el-input v-model="form.ndid" autocomplete="off" placeholder="请输入"></el-input>
</el-form-item>
<el-form-item label="设备类型:" prop="devType" class="top">
<el-select v-model="form.devType" placeholder="请选择" @change="formDevTypeChange" clearable>
<el-option
v-for="item in devTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="设备型号:" prop="devModel" class="top">
<el-select v-model="form.devModel" placeholder="请选择" clearable>
<el-option
v-for="item in formDevModelOptionsFilter"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="通讯协议:" prop="devAccessMethod" class="top">
<el-select v-model="form.devAccessMethod" placeholder="请选择" clearable>
<el-option label="MQTT" value="MQTT"></el-option>
<el-option label="CLD" value="cloud"></el-option>
</el-select>
</el-form-item>
<el-form-item label="合同号:" prop="cntractNo" class="top">
<el-input v-model="form.cntractNo" autocomplete="off" placeholder="请输入"></el-input>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="resetForm"> </el-button>
<el-button type="primary" @click="onSubmit"> </el-button>
</template>
</el-dialog>
<div class="qrcode-label">
<div class="qrcode-label-title">{{ deivce.mac }}</div>
<img class="qrcode-label-img" alt="二维码加载失败" :src="deivce.qrPath" />
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, provide, computed, reactive, nextTick } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import { queryByCode, queryByid, queryCsDictTree } from '@/api/system-boot/dictTree'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
addEquipmentDelivery,
deleteEquipmentDelivery,
editEquipmentDelivery,
batchImportDevice,
resetEquipmentDelivery,
governDeviceRegister,
portableDeviceRegister,
portableDeviceAccess
} from '@/api/cs-system-boot/device'
import html2canvas from 'html2canvas'
import { fullUrl } from '@/utils/common'
defineOptions({
name: 'govern/log/debug'
})
const devTypeOptions: any = ref([])
const deivce: any = ref({})
const ruleFormRef = ref()
const form = reactive({
cntractNo: '',
devAccessMethod: 'mqtt',
devModel: '',
devType: '',
name: '',
ndid: ''
})
const rules = reactive({
name: [{ required: true, message: '设备名不能为空', trigger: 'blur' }],
ndid: [{ required: true, message: '网络设备id不能为空', trigger: 'blur' }],
devType: [{ required: true, message: '设备类型不能为空', trigger: 'change' }],
devModel: [{ required: true, message: '设备型号不能为空', trigger: 'change' }],
devAccessMethod: [{ required: true, message: '接入方式不能为空', trigger: 'blur' }],
cntractNo: [{ required: true, message: '合同号不能为空', trigger: 'blur' }]
})
const dialogFormVisible = ref(false)
const dialogTitle = ref('新增设备')
const devModelOptions: any = ref([])
queryByCode('Device_Type').then(res => {
queryCsDictTree(res.data.id).then(res => {
devTypeOptions.value = res.data.map((item: any) => {
return {
value: item.id,
label: item.name,
...item
}
})
})
queryByid(res.data.id).then(res => {
devModelOptions.value = res.data.map((item: any) => {
return {
value: item.id,
label: item.name,
...item
}
})
})
tableStore.index()
})
const devModelOptionsFilter = computed(() => {
return devModelOptions.value.filter((item: any) => {
if (tableStore.table.params.devType) {
return item.pid == tableStore.table.params.devType
} else {
return true
}
})
})
const formDevModelOptionsFilter = computed(() => {
return devModelOptions.value.filter((item: any) => {
if (form.devType) {
return item.pid == form.devType
} else {
return true
}
})
})
const tableStore = new TableStore({
url: '/cs-device-boot/EquipmentDelivery/list',
method: 'POST',
column: [
{ title: '序号', type: 'seq',width:60 },
{ title: '设备名称', field: 'name' },
{
title: '设备类型',
field: 'devType',
formatter: row => {
return devTypeOptions.value.filter((item: any) => item.value == row.cellValue)[0]?.label
}
},
{
title: '设备型号',
field: 'devModel',
formatter: row => {
return devModelOptions.value.filter((item: any) => item.value == row.cellValue)[0]?.label
}
},
{
title: '通讯协议',
field: 'devAccessMethod',
formatter: row => {
return row.cellValue === 'MQTT' ? 'MQTT' : row.cellValue === 'cloud' ? 'CLD' : row.cellValue
}
},
{ title: '录入时间', field: 'createTime' },
{ title: '网络设备ID', field: 'ndid' },
{
title: '状态',
field: 'status',
width: 100,
render: 'tag',
custom: {
1: 'warning',
2: 'success',
3: 'primary',
4: 'primary',
5: 'warning'
},
replaceValue: {
1: '未注册',
2: '注册',
3: '接入',
4: '已取消',
5: '未接入'
}
// formatter: row => {
// return row.cellValue == 1 ? '未注册' : row.cellValue == 2 ? '注册' : '接入'
// },
},
{
title: '操作',
align: 'center',
width: '180',
render: 'buttons',
buttons: [
//直连装置注册
{
title: '注册',
type: 'primary',
icon: 'el-icon-Grid',
render: 'basicButton',
disabled: row => {
return (
(row.devType == '8b45cf6b7f5266e777d07c166ad5fa77' &&
row.devModel == 'a0d4da4b5c17b2172362a3f5a27bf217') ||
row.status != '1'
)
},
click: row => {
// 直连设备注册
ElMessageBox.confirm('确定注册该设备吗?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
governDeviceRegister({
nDid: row.ndid,
type: '4'
}).then(res => {
ElMessage.success(res.message)
tableStore.onTableAction('search', {})
})
})
.catch(e => {})
}
},
//便携式设备注册
{
title: '注册',
type: 'primary',
icon: 'el-icon-Grid',
render: 'basicButton',
disabled: row => {
// return (
// (row.devType != '8b45cf6b7f5266e777d07c166ad5fa77' &&
// row.devModel != 'a0d4da4b5c17b2172362a3f5a27bf217') ||
// row.status != '1'
// )
return true
},
click: row => {
// 便携式设备注册
ElMessageBox.confirm('确定注册该设备吗?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
portableDeviceRegister({
nDid: row.ndid
}).then(res => {
console.log(res, '8888')
ElMessage.success(res.message)
tableStore.index()
})
})
.catch(e => {})
}
},
//直连设备接入
{
title: '接入',
type: 'primary',
icon: 'el-icon-Grid',
render: 'basicButton',
disabled: row => {
return (
(row.devType == '8b45cf6b7f5266e777d07c166ad5fa77' &&
row.devModel == 'a0d4da4b5c17b2172362a3f5a27bf217') ||
row.status != '2'
)
},
click: row => {
// 直连设备接入
ElMessageBox.confirm('确定接入该设备吗?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
governDeviceRegister({
nDid: row.ndid,
type: '4'
}).then(res => {
ElMessage.success(res.message)
tableStore.onTableAction('search', {})
})
})
.catch(e => {})
}
},
//便携式设备接入
{
title: '接入',
type: 'primary',
icon: 'el-icon-Grid',
render: 'basicButton',
disabled: row => {
return (
(row.devType != '8b45cf6b7f5266e777d07c166ad5fa77' &&
row.devModel != 'a0d4da4b5c17b2172362a3f5a27bf217') ||
row.status == '3'
)
},
click: row => {
// 便携式设备接入
ElMessageBox.confirm('确定接入该设备吗?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
portableDeviceAccess({
nDid: row.ndid
}).then(res => {
ElMessage.success(res.message)
tableStore.index()
})
})
.catch(e => {})
}
},
{
title: '二维码',
type: 'primary',
icon: 'el-icon-Grid',
render: 'basicButton',
disabled: row => {
return (
row.devType == '8b45cf6b7f5266e777d07c166ad5fa77' &&
row.devModel == 'a0d4da4b5c17b2172362a3f5a27bf217'
)
},
click: row => {
deivce.value = row
deivce.value.qrPath = fullUrl(deivce.value.qrPath)
setTimeout(() => {
html2canvas(document.querySelector('.qrcode-label'), {
useCORS: true
}).then(canvas => {
let url = canvas.toDataURL('image/png')
// 下载图片
let a = document.createElement('a')
let event = new MouseEvent('click')
a.href = url
a.download = row.mac + '.png'
a.dispatchEvent(event)
})
}, 0)
}
},
{
name: 'edit',
title: '编辑',
type: 'primary',
icon: 'el-icon-EditPen',
render: 'basicButton',
click: async row => {
dialogFormVisible.value = true
dialogTitle.value = '编辑设备'
for (let key in form) {
form[key] = row[key]
}
form.id = row.id
}
},
{
name: 'del',
title: '删除',
type: 'danger',
icon: 'el-icon-Delete',
render: 'basicButton',
click: row => {
ElMessageBox.confirm('确定删除该设备吗?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
deleteEquipmentDelivery(row.id).then(res => {
ElMessage.success('删除成功!')
tableStore.onTableAction('search', {})
})
})
.catch(e => {})
}
}
]
}
],
beforeSearchFun: () => {
for (let key in tableStore.table.params) {
if (tableStore.table.params[key] === '') {
delete tableStore.table.params[key]
}
}
}
})
tableStore.table.params.orderBy = 'desc'
// 设备类型
const devTypeChange = (e: any) => {
if (!e) {
return
}
tableStore.table.params.devModel = ''
}
// 下载模版
const downLoadFile = () => {
window.open(window.location.origin + '/api/cs-device-boot/EquipmentDelivery/getExcelTemplate')
}
// 导入模版
const bulkImport = (e: any) => {
batchImportDevice(e.raw).then((res: any) => {
if (res.type === 'application/json') {
const reader = new FileReader()
reader.readAsText(res)
reader.onload = (e: any) => {
let data = JSON.parse(e.target.result)
if (data.code === 'A0000') {
ElMessage.success(data.message)
tableStore.onTableAction('search', {})
} else {
ElMessage.error(data.message)
}
}
} else {
ElMessage.error('导入失败!')
let url = window.URL.createObjectURL(res)
let link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', '导入失败.xlsx')
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
})
}
// 新增
const add = () => {
dialogFormVisible.value = true
dialogTitle.value = '新增设备'
}
// 确认
const onSubmit = () => {
ruleFormRef.value.validate((valid: any) => {
if (valid) {
if (dialogTitle.value == '新增设备') {
addEquipmentDelivery(form).then(res => {
ElMessage.success('新增成功')
resetForm()
tableStore.onTableAction('search', {})
})
} else {
editEquipmentDelivery(form).then(res => {
ElMessage.success('修改成功')
resetForm()
tableStore.onTableAction('search', {})
})
}
}
})
}
// 清空表格
const resetForm = () => {
ruleFormRef.value.resetFields()
dialogFormVisible.value = false
nextTick(() => {
// 模拟待编辑数据
let user = {
cntractNo: '',
devAccessMethod: 'mqtt',
devModel: '',
devType: '',
name: '',
ndid: ''
}
Object.assign(form, user)
})
}
const formDevTypeChange = (e: any) => {
if (!e) {
return
}
form.devModel = ''
}
provide('tableStore', tableStore)
onMounted(() => {
setTimeout(() => {
// tableStore.index()
}, 100)
})
const addMenu = () => {}
</script>
<style lang="scss" scoped>
.qrcode-label {
position: absolute;
top: 0;
right: 0;
z-index: -99;
display: flex;
align-items: center;
justify-content: center;
width: 180px;
height: 180px;
padding: 10px;
background: #fff;
flex-direction: column;
.qrcode-label-title {
margin-bottom: 10px;
font-size: 14px;
font-weight: bold;
}
.qrcode-label-img {
width: 140px;
height: 140px;
}
}
</style>

View File

@@ -0,0 +1,18 @@
<template>
<div class="harmonic">
谐波频谱
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
onMounted(() => {
console.log()
})
</script>
<style lang="scss" scoped>
.harmonic{
width:100%;
height:100%;
border: 2px solid green;
}
</style>

View File

@@ -0,0 +1,643 @@
<template>
<div class="realtrend">
<el-tabs type="border-card" v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="谐波电压含有率" name="0">
<template #label>
<span class="custom-tabs-label">
<el-icon><TrendCharts /></el-icon>
谐波电压含有率
</span>
</template>
<div class="tab_info">
<vxe-grid v-if="activeName == '0'" class="reverse-table" v-bind="gridOptions"></vxe-grid>
<div class="charts">
<MyEchart ref="barCharts1" :options="echartsData1"></MyEchart>
</div>
</div>
</el-tab-pane>
<el-tab-pane label="间谐波电压含有率" name="1">
<template #label>
<span class="custom-tabs-label">
<el-icon><TrendCharts /></el-icon>
间谐波电压含有率
</span>
</template>
<div class="tab_info">
<vxe-grid v-if="activeName == '1'" class="reverse-table" v-bind="gridOptions"></vxe-grid>
<div class="charts">
<MyEchart ref="barCharts2" :options="echartsData2"></MyEchart>
</div>
</div>
</el-tab-pane>
<el-tab-pane label="谐波电流幅值" name="2">
<template #label>
<span class="custom-tabs-label">
<el-icon><DataLine /></el-icon>
谐波电流幅值
</span>
</template>
<div class="tab_info">
<vxe-grid v-if="activeName == '2'" class="reverse-table" v-bind="gridOptions"></vxe-grid>
<div class="charts">
<MyEchart ref="barCharts3" :options="echartsData3"></MyEchart>
</div>
</div>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, reactive } from 'vue'
import { VxeGridProps, VxeGridPropTypes } from 'vxe-table'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { Platform, TrendCharts, DataLine } from '@element-plus/icons-vue'
const activeName = ref('0')
const tableList = [
{
name: '2次',
value: Math.floor(Math.random() * 101)
},
{
name: '3次',
value: Math.floor(Math.random() * 101)
},
{
name: '4次',
value: Math.floor(Math.random() * 101)
},
{
name: '5次',
value: Math.floor(Math.random() * 101)
},
{
name: '6次',
value: Math.floor(Math.random() * 101)
},
{
name: '7次',
value: Math.floor(Math.random() * 101)
},
{
name: '8次',
value: Math.floor(Math.random() * 101)
},
{
name: '9次',
value: Math.floor(Math.random() * 101)
},
{
name: '10次',
value: Math.floor(Math.random() * 101)
},
{
name: '11次',
value: Math.floor(Math.random() * 101)
},
{
name: '12次',
value: Math.floor(Math.random() * 101)
},
{
name: '13次',
value: Math.floor(Math.random() * 101)
},
{
name: '14次',
value: Math.floor(Math.random() * 101)
},
{
name: '15次',
value: Math.floor(Math.random() * 101)
},
{
name: '16次',
value: Math.floor(Math.random() * 101)
}
]
interface RowVO {
[key: string]: any
}
//谐波电压含有率
const gridOptions = ref<VxeGridProps<RowVO>>({
border: true,
showOverflow: true,
showHeader: false,
columns: [],
data: [],
columnConfig: {
resizable: true
},
align: 'center'
})
gridOptions.value = { ...defaultAttribute, ...gridOptions.value }
const myColumns = ref([
{ field: 'name', title: '次数' },
{ field: 'value', title: '谐波电压含有率(%)' }
])
const yAxisUnit: any = ref('')
myColumns.value.map(item => {
if (item.field == 'value') {
item.title =
activeName.value == '0'
? '谐波电压含有率(%)'
: activeName.value == '1'
? '间谐波电压含有率(%)'
: activeName.value == '2'
? '谐波电流幅值(A)'
: ''
yAxisUnit.value = item.title.split('(')[0]
}
})
const myData = tableList
//反转表格
const reverseTable = () => {
const buildData = myColumns.value.map(column => {
const item: any = { col0: column.title }
myData.forEach((row, index) => {
item[`col${index + 1}`] = row[column.field]
})
return item
})
const buildColumns: VxeGridPropTypes.Columns = [
{
field: 'col0',
fixed: 'left',
width: 200
}
]
myData.forEach((item, index) => {
buildColumns.push({
field: `col${index + 1}`,
minWidth: 120
})
})
gridOptions.value.data = buildData
gridOptions.value.columns = buildColumns
}
reverseTable()
const echartsData1: any = ref([]),
echartsData2: any = ref([]),
echartsData3: any = ref([]),
barCharts1 = ref(),
barCharts2 = ref(),
barCharts3 = ref()
//加载echarts
const init = () => {
const xDataList: any = [],
yDataList1: any = [],
yDataList2: any = []
tableList.map((item: any) => {
xDataList.push(item.name)
yDataList1.push(item.value)
yDataList2.push(Math.floor(Math.random() * 101) + Math.floor(Math.random() * 101))
yDataList2.push(Math.floor(Math.random() * 101) + Math.floor(Math.random() * 101))
})
if (activeName.value == '0') {
echartsData1.value = {
options: {
// backgroundColor: '#0f375f',
grid: {
top: '22%',
bottom: '15%', //也可设置left和right设置距离来控制图表的大小
left: '3%',
right: '5%'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
show: false
}
}
},
legend: {
data: ['国标限值', yAxisUnit.value],
top: '2%',
right: '2%'
// icon: 'icon'
// icon: "circle", //icon 长方形 circle 圆形 arrow箭头型 diamond菱形
// itemWidth: 14,
// itemHeight: 14,
// textStyle: {
// inside: true,
// color: '#000',
// padding: [11, 0, 10, 0],
// align: 'left',
// verticalAlign: 'center',
// fontSize: 14,
// rich: {}
// }
},
xAxis: {
name: '次数',
data: xDataList,
axisLine: {
show: true, //隐藏X轴轴线
lineStyle: {
color: '#000'
}
},
axisTick: {
show: true //隐藏X轴刻度
},
axisPointer: {
type: 'shadow'
},
axisLabel: {
show: true,
textStyle: {
color: '#000' //X轴文字颜色
}
}
},
yAxis: [
{
type: 'value',
name: '单位(' + '%' + ')',
splitLine: {
show: false
},
axisTick: {
show: true
},
axisLine: {
show: true,
lineStyle: {
color: '#000'
}
}
}
],
series: [
{
name: '国标限值',
type: 'bar',
barMaxWidth: 24, //使用的 y 轴的 index在单个图表实例中存在多个 y轴的时候有用
itemStyle: {
// normal: {
barBorderRadius: [3, 3, 0, 0],
color: '#00CC99'
// }e
},
data: yDataList1
},
{
name: yAxisUnit.value,
type: 'bar',
barMaxWidth: 24,
itemStyle: {
// normal: {
barBorderRadius: [3, 3, 0, 0],
color: '#FF9900'
// }
},
data: yDataList2
}
]
}
}
barCharts1.value.initChart()
} else if (activeName.value == '1') {
echartsData2.value = {
options: {
// backgroundColor: '#0f375f',
grid: {
top: '22%',
bottom: '15%', //也可设置left和right设置距离来控制图表的大小
left: '3%',
right: '5%'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
show: false
}
}
},
legend: {
data: ['国标限值', yAxisUnit.value],
top: '2%',
right: '2%'
// icon: 'icon'
// icon: "circle", //icon 长方形 circle 圆形 arrow箭头型 diamond菱形
// itemWidth: 14,
// itemHeight: 14,
// textStyle: {
// inside: true,
// color: '#000',
// padding: [11, 0, 10, 0],
// align: 'left',
// verticalAlign: 'center',
// fontSize: 14,
// rich: {}
// }
},
xAxis: {
name: '次数',
data: xDataList,
axisLine: {
show: true, //隐藏X轴轴线
lineStyle: {
color: '#000'
}
},
axisTick: {
show: true //隐藏X轴刻度
},
axisPointer: {
type: 'shadow'
},
axisLabel: {
show: true,
textStyle: {
color: '#000' //X轴文字颜色
}
}
},
yAxis: [
{
type: 'value',
name: '单位(' + '%' + ')',
splitLine: {
show: false
},
axisTick: {
show: true
},
axisLine: {
show: true,
lineStyle: {
color: '#000'
}
}
}
],
series: [
{
name: '国标限值',
type: 'bar',
barMaxWidth: 24, //使用的 y 轴的 index在单个图表实例中存在多个 y轴的时候有用
itemStyle: {
// normal: {
barBorderRadius: [3, 3, 0, 0],
color: '#00CC99'
// }e
},
data: yDataList1
},
{
name: yAxisUnit.value,
type: 'bar',
barMaxWidth: 24,
itemStyle: {
// normal: {
barBorderRadius: [3, 3, 0, 0],
color: '#FF9900'
// }
},
data: yDataList2
}
]
}
}
barCharts2.value.initChart()
} else if (activeName.value == '2') {
echartsData3.value = {
options: {
// backgroundColor: '#0f375f',
grid: {
top: '22%',
bottom: '15%', //也可设置left和right设置距离来控制图表的大小
left: '3%',
right: '5%'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
show: false
}
}
},
legend: {
data: ['国标限值', yAxisUnit.value],
top: '2%',
right: '2%'
// icon: 'icon'
// icon: "circle", //icon 长方形 circle 圆形 arrow箭头型 diamond菱形
// itemWidth: 14,
// itemHeight: 14,
// textStyle: {
// inside: true,
// color: '#000',
// padding: [11, 0, 10, 0],
// align: 'left',
// verticalAlign: 'center',
// fontSize: 14,
// rich: {}
// }
},
xAxis: {
name: '次数',
data: xDataList,
axisLine: {
show: true, //隐藏X轴轴线
lineStyle: {
color: '#000'
}
},
axisTick: {
show: true //隐藏X轴刻度
},
axisPointer: {
type: 'shadow'
},
axisLabel: {
show: true,
textStyle: {
color: '#000' //X轴文字颜色
}
}
},
yAxis: [
{
type: 'value',
name: '单位(' + '%' + ')',
splitLine: {
show: false
},
axisTick: {
show: true
},
axisLine: {
show: true,
lineStyle: {
color: '#000'
}
}
}
],
series: [
{
name: '国标限值',
type: 'bar',
barMaxWidth: 24, //使用的 y 轴的 index在单个图表实例中存在多个 y轴的时候有用
itemStyle: {
// normal: {
barBorderRadius: [3, 3, 0, 0],
color: '#00CC99'
// }e
},
data: yDataList1
},
{
name: yAxisUnit.value,
type: 'bar',
barMaxWidth: 24,
itemStyle: {
// normal: {
barBorderRadius: [3, 3, 0, 0],
color: '#FF9900'
// }
},
data: yDataList2
}
]
}
}
barCharts3.value.initChart()
}
}
const handleClick = (tab: any, event: any) => {
activeName.value = tab.index
myColumns.value.map(item => {
if (item.field == 'value') {
item.title =
activeName.value == '0'
? '谐波电压含有率(%)'
: activeName.value == '1'
? '间谐波电压含有率(%)'
: activeName.value == '2'
? '谐波电流幅值(A)'
: ''
yAxisUnit.value = item.title.split('(')[0]
}
})
reverseTable()
init()
}
onMounted(() => {
init()
})
</script>
<style lang="scss" scoped>
.realtrend {
width: 100%;
height: 100%;
.table_info {
width: 100%;
height: auto;
overflow-x: auto;
.table {
width: auto;
height: auto;
border: 2px solid #eee;
display: flex;
flex-direction: column;
.thead {
width: 100%;
height: 40px;
display: flex;
border-bottom: 2px solid #eee;
.thead_left {
width: 200px !important;
height: 100%;
line-height: 40px;
text-align: center;
font-size: 14px;
font-weight: 800;
}
.thead_right {
flex: 1;
display: flex;
.thead_right_item {
flex: none;
width: 100px;
text-align: center;
line-height: 40px;
border-left: 1px solid #eee;
}
}
}
.tbody {
width: 100%;
height: 40px;
display: flex;
.tbody_left {
width: 200px !important;
height: 100%;
line-height: 40px;
text-align: center;
font-size: 14px;
font-weight: 800;
}
.tbody_right {
flex: 1;
display: flex;
.tbody_right_item {
flex: none;
width: 100px;
text-align: center;
line-height: 40px;
border-left: 1px solid #eee;
}
}
}
}
}
}
.reverse-table {
// max-height:120px !important;
}
.reverse-table .vxe-body--row .vxe-body--column:first-child {
background-color: #f8f8f9;
}
::v-deep .vxe-table--render-wrapper {
height: 90px !important;
max-height: 90px !important;
overflow-x: auto !important;
min-height: 0 !important;
}
::v-deep .body--wrapper {
height: 90px !important;
max-height: 90px !important;
min-height: 0 !important;
}
.tab_info {
width: 100%;
height: calc(100vh - 450px);
// overflow: auto;
// padding-bottom: 20px;
.charts {
width: 100%;
margin-top: 10px;
height: calc(100vh - 550px);
}
}
.custom-tabs-label {
display: flex;
align-items: center;
}
</style>

View File

@@ -0,0 +1,18 @@
<template>
<div class="record">
实时录波
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
onMounted(() => {
console.log()
})
</script>
<style lang="scss" scoped>
.record{
width:100%;
height:100%;
border: 2px solid red;
}
</style>

View File

@@ -1,140 +1,62 @@
<template>
<div>
<vxe-table
border
show-footer
ref="tableRef"
v-bind="defaultAttribute"
height="70"
align="center"
stripe
:loading="loading"
:print-config="{}"
:column-config="{ resizable: false, width: 90 }"
:data="tableData"
style="width: 100%; margin-top: 10px"
>
<div v-if="tableIndex == 0">
<vxe-colgroup title="电压有效值(kV)">
<vxe-column field="a" title="AB相"></vxe-column>
<vxe-column field="b" title="BC相"></vxe-column>
<vxe-column field="c" title="CA相"></vxe-column>
</vxe-colgroup>
<vxe-colgroup title="电流有效值(A)">
<vxe-column field="a" title="A相"></vxe-column>
<vxe-column field="b" title="B相"></vxe-column>
<vxe-column field="c" title="C相"></vxe-column>
</vxe-colgroup>
<vxe-colgroup title="基波电压幅值(kV)">
<vxe-column field="a" title="A相"></vxe-column>
<vxe-column field="b" title="B相"></vxe-column>
<vxe-column field="c" title="C相"></vxe-column>
</vxe-colgroup>
<vxe-colgroup title="基波电压相位(°)">
<vxe-column field="a" title="A相"></vxe-column>
<vxe-column field="b" title="B相"></vxe-column>
<vxe-column field="c" title="C相"></vxe-column>
</vxe-colgroup>
<vxe-colgroup title="基波电流幅值(A)">
<vxe-column field="a" title="A相"></vxe-column>
<vxe-column field="b" title="B相"></vxe-column>
<vxe-column field="c" title="C相"></vxe-column>
</vxe-colgroup>
<vxe-colgroup title="基波电流相位(°)">
<vxe-column field="a" title="A相"></vxe-column>
<vxe-column field="b" title="B相"></vxe-column>
<vxe-column field="c" title="C相"></vxe-column>
</vxe-colgroup>
<div v-if="tableData.length != 0">
<!-- div设计table -->
<div class="table" v-for="(item, index) in columnsData" :key="index">
<!-- 单层表头 -->
<div class="thead">
<div class="thead_top">
{{ item[0].showName ? item[0].showName : '' }}({{ item[0].unit }})
</div>
<div class="thead_bot">
<div class="thead_bot_cell" v-for="(vv, key) in item" :key="key">
{{ vv.phase + ' ' }}
</div>
</div>
</div>
<div v-if="tableIndex == 1">
<vxe-colgroup title="电压偏差(%)">
<vxe-column field="a" title="AB相"></vxe-column>
<vxe-column field="b" title="BC相"></vxe-column>
<vxe-column field="c" title="CA相"></vxe-column>
</vxe-colgroup>
<vxe-colgroup title="电压总谐波畸变率(%)">
<vxe-column field="a" title="A相"></vxe-column>
<vxe-column field="b" title="BC相"></vxe-column>
<vxe-column field="c" title="CA相"></vxe-column>
</vxe-colgroup>
<vxe-colgroup title="电流总谐波畸变率(%)">
<vxe-column field="a" title="A相"></vxe-column>
<vxe-column field="b" title="BC相"></vxe-column>
<vxe-column field="c" title="CA相"></vxe-column>
</vxe-colgroup>
<vxe-colgroup title="电压不平衡度(%)">
<vxe-column field="a" title="A相"></vxe-column>
<vxe-column field="b" title="BC相"></vxe-column>
<vxe-column field="c" title="CA相"></vxe-column>
</vxe-colgroup>
<vxe-column field="a" width="170" title="电流不平衡度(%)"></vxe-column>
<vxe-column field="b" width="170" title="频率(Hz)"></vxe-column>
<vxe-column field="c" width="170" title="基波电流相位(°)"></vxe-column>
<!-- 有合并表头的数据 -->
<div class="tbody">
<div class="tbody_cell" v-for="(vv, key) in item" :key="key">
{{
tableData.find(item => {
return item.anotherName == vv.showName && item.phase == vv.phase
})?.statisticalData
? tableData.find(item => {
return item.anotherName == vv.showName && item.phase == vv.phase
})?.statisticalData
: '/'
}}
</div>
</div>
<div v-if="tableIndex == 2">
<vxe-colgroup title="有功功率(kV)">
<vxe-column field="a" title="A相"></vxe-column>
<vxe-column field="b" title="B相"></vxe-column>
<vxe-column field="c" title="C相"></vxe-column>
<vxe-column field="c" title="总有功功率"></vxe-column>
</vxe-colgroup>
<vxe-colgroup title="无功功率(kV)">
<vxe-column field="a" title="A相"></vxe-column>
<vxe-column field="b" title="B相"></vxe-column>
<vxe-column field="c" title="C相"></vxe-column>
<vxe-column field="c" title="总无功功率"></vxe-column>
</vxe-colgroup>
<vxe-colgroup title="视在功率(kV)">
<vxe-column field="a" title="A相"></vxe-column>
<vxe-column field="b" title="B相"></vxe-column>
<vxe-column field="c" title="C相"></vxe-column>
<vxe-column field="c" title="总视在功率"></vxe-column>
</vxe-colgroup>
<vxe-colgroup title="功率因数">
<vxe-column field="a" title="A相"></vxe-column>
<vxe-column field="b" title="B相"></vxe-column>
<vxe-column field="c" title="C相"></vxe-column>
<vxe-column field="c" title="总功率因数"></vxe-column>
</vxe-colgroup>
</div>
</vxe-table>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, nextTick, onMounted } from 'vue'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import { VxeTablePropTypes, VxeTableInstance, VxeToolbarInstance } from 'vxe-table'
interface RowVO {
a: string
b: string
c: string
}
import { getRealTimeTableList } from '@/api/cs-device-boot/EquipmentDelivery'
const loading = ref(false)
const tableData = ref<RowVO[]>([])
const tableRef = ref<VxeTableInstance<RowVO>>()
const toolbarRef = ref<VxeToolbarInstance>()
const tableData: any = ref([])
loading.value = true
nextTick(() => {
// 将表格和工具栏进行关联
const $table = tableRef.value
const $toolbar = toolbarRef.value
if ($table && $toolbar) {
$table.connect($toolbar)
}
})
const columnsData: any = ref([])
const getColumns = () => {
getRealTimeTableList().then(res => {
columnsData.value = res.data
})
}
nextTick(() => {})
onMounted(() => {
getColumns()
loading.value = false
})
const tableIndex: any = ref(null)
const getTableData = (val: any, list: any) => {
tableIndex.value = val
const getTableData = (list: any) => {
tableData.value = list
loading.value = false
columnsData.value.map((item: any) => {
item.map((vv: any) => {
vv.statisticalData = list.find((kk: any) => {
return kk.anotherName == vv.showName && kk.phase == vv.phase
})?.statisticalData
})
})
}
defineExpose({ getTableData })
</script>
@@ -143,4 +65,58 @@ defineExpose({ getTableData })
// ::v-deep .vxe-table--empty-content{
// display: none !important;
// }
.table {
width: 100%;
height: 120px;
border: 1px solid #eee;
border-bottom: 2px solid #eee;
margin-bottom: 20px;
display: flex;
flex-direction: column;
.thead {
width: 100%;
height: auto;
background: #f4f6f9;
text-align: center;
display: flex;
flex-direction: column;
.thead_top {
width: 100%;
height: 40px;
line-height: 40px;
border: 1px solid #eee;
color: #111;
font-size: 14px;
font-weight: 800;
}
.thead_bot {
width: 100%;
height: 40px;
line-height: 40px;
display: flex;
color: #111;
font-size: 14px;
font-weight: 800;
.thead_bot_cell {
flex: 1;
border: 1px solid #eee;
}
}
}
.tbody {
flex: 1;
display: flex;
text-align: center;
.tbody_cell {
flex: 1;
text-align: center;
line-height: 40px;
border: 1px solid #eee;
border-bottom: 0;
}
}
.tbody:hover {
background: #f4f6f9;
}
}
</style>

View File

@@ -3,29 +3,57 @@
<div class="view_top">
<!-- 左侧仪表盘 -->
<div class="view_top_left">
<div class="left_charts"><MyEchart ref="pieChartRef" :options="echartsData"></MyEchart></div>
<div class="left_charts"><MyEchart ref="pieChartRef" :options="echartsData"></MyEchart></div>
<div class="left_charts"><MyEchart ref="pieChartRef" :options="echartsData"></MyEchart></div>
<div class="left_charts_title">电压有效值</div>
<div class="left_charts"><MyEchart ref="pieChart1" :options="echartsDataV1"></MyEchart></div>
<div class="left_charts"><MyEchart ref="pieChart2" :options="echartsDataV2"></MyEchart></div>
<div class="left_charts"><MyEchart ref="pieChart3" :options="echartsDataV3"></MyEchart></div>
</div>
<div class="view_top_mid">
<div class="mid_charts"><MyEchart ref="pieChartRef" :options="echartsData1"></MyEchart></div>
<div class="mid_charts_title">基波电压/电流幅值(相位)</div>
<div class="mid_charts"><MyEchart :options="echartsData1"></MyEchart></div>
</div>
<!-- 右侧仪表盘 -->
<div class="view_top_right">
<div class="right_charts"><MyEchart ref="pieChartRef" :options="echartsData"></MyEchart></div>
<div class="right_charts"><MyEchart ref="pieChartRef" :options="echartsData"></MyEchart></div>
<div class="right_charts"><MyEchart ref="pieChartRef" :options="echartsData"></MyEchart></div>
<div class="right_chartsitle">电流有效值</div>
<div class="right_charts"><MyEchart ref="pieChart4" :options="echartsDataA1"></MyEchart></div>
<div class="right_charts"><MyEchart ref="pieChart5" :options="echartsDataA2"></MyEchart></div>
<div class="right_charts"><MyEchart ref="pieChart6" :options="echartsDataA3"></MyEchart></div>
</div>
</div>
<div class="view_bot">
<div class="view_bot_tables">
<tableInfo ref="tableInfoRef1" />
</div>
<div class="view_bot_tables">
<tableInfo ref="tableInfoRef2" />
</div>
<div class="view_bot_tables">
<tableInfo ref="tableInfoRef3" />
<!-- <tableInfo ref="tableInfoRef" /> -->
<!-- 表格数据 -->
<div v-if="tableData.length != 0">
<!-- div设计table -->
<div class="table" v-for="(item, index) in columnsData" :key="index">
<!-- 单层表头 -->
<div class="thead">
<div class="thead_top">
{{ item[0].showName ? item[0].showName : '' }}({{ item[0].unit }})
</div>
<div class="thead_bot">
<div class="thead_bot_cell" v-for="(vv, key) in item" :key="key">
{{ vv.phase + ' ' }}
</div>
</div>
</div>
<!-- 有合并表头的数据 -->
<div class="tbody">
<div class="tbody_cell" v-for="(vv, key) in item" :key="key">
{{
tableData.find(item => {
return item.anotherName == vv.showName && item.phase == vv.phase
})?.statisticalData
? tableData.find(item => {
return item.anotherName == vv.showName && item.phase == vv.phase
})?.statisticalData
: '/'
}}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@@ -33,12 +61,27 @@
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { getRealTimeTableList } from '@/api/cs-device-boot/EquipmentDelivery'
import tableInfo from './components/tableInfo.vue'
import * as echarts from 'echarts'
import { split } from 'lodash-es'
const pieChartRef: any = ref()
const pieChart1: any = ref()
const pieChart2: any = ref()
const pieChart3: any = ref()
const pieChart4: any = ref()
const pieChart5: any = ref()
const pieChart6: any = ref()
const echartsData: any = ref({})
const echartsData1: any = ref({})
//电压有效值
const echartsDataV1: any = ref({})
const echartsDataV2: any = ref({})
const echartsDataV3: any = ref({})
//电流有效值
const echartsDataA1: any = ref({})
const echartsDataA2: any = ref({})
const echartsDataA3: any = ref({})
//渲染echarts
const init = () => {
echartsData.value = {
@@ -87,251 +130,22 @@ const init = () => {
data: [
{
value: 15,
name: '违规率'
name: 'A相'
}
]
}
]
}
}
echartsDataV1.value = echartsData.value
echartsDataV2.value = echartsData.value
echartsDataV3.value = echartsData.value
echartsDataA1.value = echartsData.value
echartsDataA2.value = echartsData.value
echartsDataA3.value = echartsData.value
//中间指针图
echartsData1.value = {
// options: {
// // backgroundColor: '#001533',
// tooltip: {
// format: function (params) {
// console.log(params)
// }
// },
// series: [
// //外圈
// {
// radius: '100%',
// min: -150,
// max: 180,
// startAngle: -90,
// endAngle: 270,
// pointer: {
// show: true,
// length: '80%',
// radius: '20%',
// width: 6 //指针粗细
// },
// itemStyle: {
// normal: {
// color: 'rgb(0,191,255)'
// }
// },
// // axisLine: {
// // show: true,
// // fontSize: 20,
// // lineStyle: {
// // width: 0,
// // color: [[1, '#01b4e0']]
// // }
// // },
// axisLine: {
// show: true,
// // 坐标轴线
// lineStyle: {
// color: [[1, '#F42E47']], // 属性lineStyle控制线条样式
// width: 2
// },
// interval: 0
// },
// splitLine: {
// length: 10,
// lineStyle: {
// width: 2,
// color: '#01b4e0',
// distance: 5
// }, //刻度节点线
// splitNumber: 5
// },
// splitNumber: 11,
// axisTick: {
// show: false
// },
// axisLabel: {
// show: true,
// fontSize: 14,
// color: '#000',
// formatter: function (v: any) {
// console.log(v, '00000000000')
// switch (v + '') {
// case '-122.5':
// return '-120'
// case '-95':
// return '-90'
// case '-60':
// return '-60'
// case '-67.5':
// return '-60'
// case '-40':
// return '-30'
// case '-12.5':
// return '0'
// case '42.5':
// return '30'
// case '70':
// return '60'
// case '97.5':
// return '90'
// case '125':
// return '120'
// case '152.5':
// return '150'
// case '-180':
// return ''
// case '180':
// return '180'
// default:
// return v
// }
// }
// },
// detail: {
// show: false,
// textStyle: {
// fontSize: 30,
// fontWeight: '700',
// color: '#67d9fe'
// }
// },
// data: [
// {
// name: '',
// value: 150,
// itemStyle: {
// color: 'red'
// }
// },
// {
// name: '',
// value: 60,
// itemStyle: {
// color: '#DAA521'
// }
// },
// {
// name: '',
// value: 90,
// itemStyle: {
// color: 'green'
// }
// }
// ]
// },
// //内圈
// {
// radius: '50%',
// splitNumber: 11,
// startAngle: 0,
// endAngle: 360,
// min: -150,
// max: 180,
// axisLine: {
// show: true,
// // 坐标轴线
// lineStyle: {
// color: [[1, '#1C9EE9']], // 属性lineStyle控制线条样式
// width: 2,
// type: 'dashed'
// }
// },
// pointer: {
// show: true,
// length: '80%',
// radius: '20%',
// width: 8 //指针粗细
// },
// itemStyle: {
// // show: false,
// normal: {
// color: 'rgb(0,191,255)'
// }
// },
// splitLine: {
// length: 5,
// interval: 30,
// lineStyle: {
// width: 2,
// color: 'green',
// distance: -20
// } //刻度节点线
// },
// axisTick: {
// show: false
// },
// axisLabel: {
// show: true,
// itemStyle: {
// interval: 0
// },
// formatter: function (v: any) {
// console.log(v, '00000000000')
// switch (v + '') {
// case '-122.5':
// return '-120'
// case '-95':
// return '-90'
// case '-60':
// return '-60'
// case '-67.5':
// return '-60'
// case '-40':
// return '-30'
// case '-12.5':
// return '0'
// case '42.5':
// return '30'
// case '70':
// return '60'
// case '97.5':
// return '90'
// case '125':
// return '120'
// case '152.5':
// return '150'
// case '-180':
// return ''
// case '180':
// return '180'
// default:
// return v
// }
// }
// },
// detail: {
// show: false
// },
// data: [
// {
// name: '',
// value: 110,
// itemStyle: {
// color: 'red'
// }
// },
// {
// name: '',
// value: 70,
// itemStyle: {
// color: '#DAA521'
// }
// },
// {
// name: '',
// value: 20,
// itemStyle: {
// color: 'green'
// }
// }
// ]
// }
// ]
// }
options: {
grid: {
top: 230
@@ -1102,7 +916,7 @@ const init = () => {
show: true,
lineStyle: {
color: [
[0.25, '#9D322D'],
[0.25, '#9D322D'],
[0.5, '#9D322D'],
[0.75, '#9D322D'],
[1, '#9D322D']
@@ -1186,32 +1000,125 @@ const init = () => {
echartsData1.value.options.series[i].startAngle = 90
echartsData1.value.options.series[i].endAngle = -270
echartsData1.value.options.series[i].center = ['50%', '50%']
// option.series[i].axisTick = {show: false};
// option.series[i].axisLabel = {show: false};
// optionThree.series[i].pointer = {show: false};
// optionThree.series[i].detail = {show: false};
}
}
//渲染table表头
const tableInfoRef1: any = ref(null)
const tableInfoRef2: any = ref(null)
const tableInfoRef3: any = ref(null)
const initTableHead = () => {
const list: any = []
for (let index = 0; index < 1; index++) {
list.push({
a: Math.floor(Math.random() * (100 + 1)),
b: Math.floor(Math.random() * (100 + 1)),
c: Math.floor(Math.random() * (100 + 1))
//接收父组件传递的table数据
const tableInfoRef: any = ref(null)
const dataList: any = ref([])
const listV: any = ref([])
const listA: any = ref([])
const loading = ref(false)
//定义表格所需要的数据
const tableData: any = ref([])
loading.value = true
const columnsData: any = ref([])
const getColumns = () => {
getRealTimeTableList().then(res => {
columnsData.value = res.data
})
}
//处理表格数据
const getTableData = (list: any) => {
tableData.value = list
loading.value = false
columnsData.value.map((item: any) => {
item.map((vv: any) => {
vv.statisticalData = list.find((kk: any) => {
return kk.anotherName == vv.showName && kk.phase == vv.phase
})?.statisticalData
})
}
tableInfoRef1.value.getTableData(0, list)
tableInfoRef2.value.getTableData(1, list)
tableInfoRef3.value.getTableData(2, list)
})
}
//获取实时数据
const getRealTimeData = (val: any) => {
dataList.value = val
dataList.value.map((item: any, index: any) => {
if (item.anotherName == '相电压总有效值') {
listV.value.push(item)
}
if (item.anotherName == '线电压总有效值') {
listA.value.push(item)
}
})
echartsDataV1.value.options.series[0].data = [
{
name:
listV.value.find((item: any) => {
return item.phase == 'A'
})?.phase + '相',
value: listV.value.find((item: any) => {
return item.phase == 'A'
})?.statisticalData
}
]
pieChart1.value.initChart()
echartsDataV2.value.options.series[0].data = [
{
name:
listV.value.find((item: any) => {
return item.phase == 'B'
})?.phase + '相',
value: listV.value.find((item: any) => {
return item.phase == 'B'
})?.statisticalData
}
]
pieChart2.value.initChart()
echartsDataV3.value.options.series[0].data = [
{
name:
listV.value.find((item: any) => {
return item.phase == 'C'
})?.phase + '相',
value: listV.value.find((item: any) => {
return item.phase == 'C'
})?.statisticalData
}
]
pieChart3.value.initChart()
echartsDataA1.value.options.series[0].data = [
{
name:
listA.value.find((item: any) => {
return item.phase == 'AB'
})?.phase + '相',
value: listA.value.find((item: any) => {
return item.phase == 'AB'
})?.statisticalData
}
]
pieChart4.value.initChart()
echartsDataA2.value.options.series[0].data = [
{
name:
listA.value.find((item: any) => {
return item.phase == 'BC'
})?.phase + '相',
value: listA.value.find((item: any) => {
return item.phase == 'BC'
})?.statisticalData
}
]
pieChart5.value.initChart()
echartsDataA3.value.options.series[0].data = [
{
name:
listA.value.find((item: any) => {
return item.phase == 'CA'
})?.phase + '相',
value: listA.value.find((item: any) => {
return item.phase == 'CA'
})?.statisticalData
}
]
pieChart6.value.initChart()
getColumns()
getTableData(val)
}
defineExpose({ getRealTimeData })
onMounted(() => {
init()
initTableHead()
})
</script>
<style lang="scss" scoped>
@@ -1232,16 +1139,18 @@ onMounted(() => {
.view_top_right {
width: 30%;
height: 100%;
padding: 10px;
display: flex;
flex-direction: column;
align-items: center;
border: 1px solid #eee;
.left_charts,
.right_charts {
flex: none;
width: 100%;
height: 120px;
border: 1px solid #eee;
margin-bottom: 10px;
margin-bottom: 16px;
padding: 10px;
}
}
@@ -1250,11 +1159,23 @@ onMounted(() => {
border: 1px solid #eee;
margin: 0 10px;
padding: 10px;
height: 450px;
.mid_charts {
width: 100%;
height: 100%;
}
}
.left_charts_title,
.mid_charts_title,
.right_charts_title {
width: 100%;
height: 20px;
text-align: left;
font-weight: 800;
font-weight: 16px;
line-height: 20px;
}
}
.view_bot {
min-height: 300px;
@@ -1268,4 +1189,58 @@ onMounted(() => {
.view::-webkit-scrollbar {
display: none;
}
.table {
width: 100%;
height: 120px;
border: 1px solid #eee;
border-bottom: 2px solid #eee;
margin-bottom: 20px;
display: flex;
flex-direction: column;
.thead {
width: 100%;
height: auto;
background: #f4f6f9;
text-align: center;
display: flex;
flex-direction: column;
.thead_top {
width: 100%;
height: 40px;
line-height: 40px;
border: 1px solid #eee;
color: #111;
font-size: 14px;
font-weight: 800;
}
.thead_bot {
width: 100%;
height: 40px;
line-height: 40px;
display: flex;
color: #111;
font-size: 14px;
font-weight: 800;
.thead_bot_cell {
flex: 1;
border: 1px solid #eee;
}
}
}
.tbody {
flex: 1;
display: flex;
text-align: center;
.tbody_cell {
flex: 1;
text-align: center;
line-height: 40px;
border: 1px solid #eee;
border-bottom: 0;
}
}
.tbody:hover {
background: #f4f6f9;
}
}
</style>

View File

@@ -429,12 +429,12 @@ const open = async (val: any, id: any) => {
//0未绑定数据 1 已绑定数据
//获取未绑定树形数据
getDeviceList({ id: id, isTrueFlag: 0 }).then(res => {
deviceInfoTreeRef1.value.getTreeList(res.data)
// deviceInfoTreeRef1.value.getTreeList(res.data)
unBindList.value = res.data
})
//获取已绑定树形数据
getDeviceList({ id: id, isTrueFlag: 1 }).then(res => {
deviceInfoTreeRef2.value.getTreeList(res.data)
// deviceInfoTreeRef2.value.getTreeList(res.data)
bindList.value = res.data
})
activeName.value = 0

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,169 @@
<template>
<div class="default-main" :style="height">
<splitpanes style="height: 100%; background: #fff" class="default-theme" id="navigation-splitpanes">
<pane :size="size">
<PointTree
:default-expand-all="false"
@node-click="handleNodeClick"
@init="handleNodeClick"
></PointTree>
</pane>
<pane style="background: #fff" :style="height">
<div class="default-main">
<TableHeader ref="TableHeaderRef" datePicker>
<template v-slot:select>
<el-form-item label="模板策略">
<el-select
v-model="Template"
@change="changetype"
placeholder="请选择模版"
value-key="id"
>
<el-option
v-for="item in templatePolicy"
:key="item.id"
:label="item.name"
:value="item"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="报表类型:">
<el-select
:disabled="true"
v-model="reportForm"
:popper-append-to-body="false"
placeholder="请选择报表类型"
>
<el-option
v-for="item in reportFormList"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
</template>
<template #operation>
<el-button icon="el-icon-Download" type="primary" @click="exportEvent">导出excel</el-button>
</template>
</TableHeader>
<div class="box">
<div id="luckysheet" :style="`height: calc(${tableStore.table.height} + 45px)`"></div>
</div>
</div>
</pane>
</splitpanes>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, provide } from 'vue'
import TableStore from '@/utils/tableStore'
import PointTree from '@/components/tree/govern/pointTree.vue'
import TableHeader from '@/components/table/header/index.vue'
import { useDictData } from '@/stores/dictData'
import { mainHeight } from '@/utils/layout'
import { getTemplateByDept } from '@/api/harmonic-boot/luckyexcel'
import { exportExcel } from '@/views/system/reportForms/export.js'
import 'splitpanes/dist/splitpanes.css'
import { Splitpanes, Pane } from 'splitpanes'
import data from './123.json'
defineOptions({
name: 'reportCore/statistics'
})
const height = mainHeight(20)
const size = ref(0)
const dictData = useDictData()
const TableHeaderRef = ref()
const dotList: any = ref({})
const Template: any = ref({})
const reportForm: any = ref('')
const templatePolicy: any = ref([])
const reportFormList: any = ref([
{
value: '1',
label: '分析报表'
},
{
value: '2',
label: '统计报表'
},
{
value: '3',
label: '自定义报表'
}
])
const tableStore = new TableStore({
// url: '/harmonic-boot/customReport/getCustomReport',
method: 'POST',
column: [],
beforeSearchFun: () => {
tableStore.table.params.tempId = Template.value.id
tableStore.table.params.lineId = dotList.value.id
},
loadCallback: () => {
console.log(tableStore.table.data)
tableStore.table.data.forEach((item: any) => {
item.celldata.forEach((k: any) => {
item.data[k.r][k.c].v = k.v
})
})
luckysheet.create({
container: 'luckysheet',
title: '', // 表 头名
lang: 'zh', // 中文
showtoolbar: false, // 是否显示工具栏
showinfobar: false, // 是否显示顶部信息栏
showsheetbar: true, // 是否显示底部sheet按钮
data: data
// tableStore.table.data
})
}
})
provide('tableStore', tableStore)
onMounted(() => {
const dom = document.getElementById('navigation-splitpanes')
if (dom) {
size.value = Math.round((180 / dom.offsetHeight) * 100)
}
luckysheet.create({
container: 'luckysheet',
title: '', // 表 头名
lang: 'zh', // 中文
showtoolbar: false, // 是否显示工具栏
showinfobar: false, // 是否显示顶部信息栏
showsheetbar: true, // 是否显示底部sheet按钮
data: data
// tableStore.table.data
})
})
// getTemplateByDept({ id: dictData.state.area[0].id }).then((res: any) => {
// templatePolicy.value = res.data
// Template.value = res.data[0]
// reportForm.value = res.data[0]?.reportForm
// })
const changetype = (val: any) => {
reportForm.value = val.reportForm
}
const handleNodeClick = (data: any, node: any) => {
if (data.level == 6) {
dotList.value = data
tableStore.index()
}
}
const exportEvent = () => {
exportExcel(luckysheet.getAllSheets(), '统计报表下载')
}
</script>
<style lang="scss" scoped>
.splitpanes.default-theme .splitpanes__pane {
background: #eaeef1;
}
.box {
padding: 10px;
}
</style>