通讯链路:链路参数表格

This commit is contained in:
高云鹏 2024-08-02 15:58:35 +08:00
parent c3fde1e875
commit f38aa8731f
9 changed files with 1216 additions and 9 deletions

View File

@ -12,6 +12,19 @@
},
"dependencies": {
"@element-plus/icons-vue": "2.3.1",
"@univerjs/core": "^0.2.4",
"@univerjs/design": "^0.2.4",
"@univerjs/docs": "^0.2.4",
"@univerjs/docs-ui": "^0.2.4",
"@univerjs/engine-formula": "^0.2.4",
"@univerjs/engine-numfmt": "^0.2.4",
"@univerjs/engine-render": "^0.2.4",
"@univerjs/facade": "^0.2.4",
"@univerjs/rpc": "^0.2.4",
"@univerjs/sheets": "^0.2.4",
"@univerjs/sheets-formula": "^0.2.4",
"@univerjs/sheets-ui": "^0.2.4",
"@univerjs/ui": "^0.2.4",
"@vueuse/core": "10.10.0",
"axios": "1.7.2",
"countup.js": "2.8.0",

View File

@ -12,6 +12,9 @@ import {
linkType,
} from '/@/views/backend/node/type'
import createAxios from '/@/utils/axios'
import { encrypt_aes } from '/@/utils/crypto'
import { useAdminInfo } from '/@/stores/adminInfo'
const adminInfo = useAdminInfo()
export const getNodeListReq = () => {
return createAxios<never, RequestReturnType<nodeType[]>>({
@ -83,7 +86,7 @@ export const addLinkListReq = (data: addLinkType) => {
})
}
export const downloadNodeReq = (data:any) => {
export const downloadNodeReq = (data: any) => {
return createAxios({
url: '',
method: 'post',
@ -91,10 +94,75 @@ export const downloadNodeReq = (data:any) => {
})
}
export const uploadNodeReq = (data:any) => {
export const uploadNodeReq = (data: any) => {
return createAxios({
url: '',
method: 'post',
data: data,
})
}
export const getMappingListReq = (data: any) => {
return createAxios({
url: '/api/node/link/getMappingList',
method: 'post',
data: data,
})
}
export const saveMappingListReq = (data: any) => {
return createAxios<never, RequestReturnType>({
url: '/api/node/link/saveMappingList',
method: 'post',
data: data,
})
}
export const bindDeviceMeasReq = (data: any) => {
return createAxios({
url: '/api/node/link/bindDeviceMeas',
method: 'post',
data: data,
})
}
export const getBindDeviceTreeReq = (data: any) => {
return createAxios({
url: '/api/node/link/getBindDeviceTree',
method: 'post',
data: data,
})
}
export const downloadMappingListReq = (data: any) => {
return createAxios(
{
url: '/api/node/link/exportMappingList',
method: 'post',
data: data,
responseType: 'blob',
},
{
reductDataFormat: false,
}
)
}
export const uploadMappingListReq = (data: any, v: string) => {
const token = encrypt_aes(adminInfo.token, v)
return createAxios<never, RequestReturnType>(
{
url: '/api/node/link/importMappingList',
method: 'post',
data: data,
headers: {
'Content-Type': 'multipart/form-data',
v,
token,
},
},
{
customEncrypt: true,
}
)
}

View File

@ -65,6 +65,11 @@ const staticRoutes: Array<RouteRecordRaw> = [
title: pageTitle('noPower'),
},
},
{
path: '/univer',
name: 'univer',
component: () => import('/@/views/backend/node/univer.vue'),
},
]
const staticFiles: Record<string, Record<string, RouteRecordRaw>> = import.meta.glob('./static/*.ts', { eager: true })

View File

@ -622,7 +622,7 @@ const closeAttributeForm = () => {
attributeFormRef.value?.resetFields()
}
const submitAttributeForm = () => {
attributeFormRef.value?.validate((valid) => {
attributeFormRef.value?.validate((valid: boolean) => {
if (valid) {
if (attributeFormTitle.value === AttributeDialogTitleStateType['add']) {
attributeForm.value.iotModelId = curContextMenuTreeData.value!.id!
@ -681,7 +681,7 @@ const closeServiceForm = () => {
serviceFormRef.value?.resetFields()
}
const submitServiceForm = () => {
serviceFormRef.value?.validate((valid) => {
serviceFormRef.value?.validate((valid: boolean) => {
if (valid) {
if (serviceFormTitle.value === serviceDialogTitleStateType['add']) {
serviceForm.value.iotModelId = curContextMenuTreeData.value!.id!

View File

@ -322,7 +322,7 @@ const addInstitutional = (rightClick = false) => {
const submitAddForm = () => {
console.log(formModel.value)
if (!formRef.value) return
formRef.value.validate((valid) => {
formRef.value.validate((valid:boolean) => {
if (valid) {
if (dialogTitle.value === '新增机构') {
formModel.value.parentOrgId = formModel.value.parentOrgId ?? '0'

View File

@ -98,6 +98,8 @@
<el-table-column fixed="right" label="操作" min-width="80" align="center">
<template #default="scope">
<div class="tableOperate">
<a @click="openlinkPoint(scope.row)">测点</a>
<a>|</a>
<a @click="editLinkList(scope.row)">编辑</a>
<a>|</a>
<el-popconfirm title="确定删除么?" @confirm="delLinkList(scope.row)">
@ -175,6 +177,10 @@ import {
import { getInstitutionalTreeListReq } from '/@/api/backend/org/request'
import { debounce } from 'lodash-es'
import ProtocolComponent from './protocol.vue'
import { useRouter, useRoute } from 'vue-router'
const router = useRouter()
const route = useRoute()
const searchTreeInput = ref('')
@ -362,6 +368,7 @@ const getNodeList = () => {
clickTreeData.value = res.data![0]
nextTick(() => {
nodeTreeRef.value?.setCurrentKey(res.data![0].id)
getLinkData(res.data![0].id!)
})
} else {
ElMessage.error(res.msg ?? '查询失败')
@ -439,7 +446,7 @@ const delLinkList = (row: linkType) => {
})
}
const submitLinkForm = () => {
linkFormRef.value?.validate((valid) => {
linkFormRef.value?.validate((valid: boolean) => {
if (valid) {
if (linkTitle.value === '新增链路') {
addLinkListReq(linkForm.value)
@ -531,9 +538,18 @@ const openParams = (data: linkType) => {
ElMessage.warning('请先设置协议类型')
}
}
getNodeList().then(() => {
getLinkData(clickTreeData.value!.id!)
})
const openlinkPoint = (data: linkType) => {
router.push({
name: 'univer',
query: {
protocol: data.protocol,
id: data.id,
prevPath: route.path,
},
})
}
getNodeList()
</script>
<style lang="scss" scoped>

View File

@ -0,0 +1,552 @@
<template>
<Container :has-aside="false">
<template #mainHeader>
<div class="header">
<el-button @click="openCorrectionPoint">关联测点</el-button>
<div class="rightOperate">
<el-upload ref="uploadRef" :show-file-list="false" :limit="1" :http-request="upload" :on-exceed="handleExceed">
<template #trigger>
<el-button>上传</el-button>
</template>
</el-upload>
<el-popconfirm @confirm="download" title="确认下载么?">
<template #reference>
<el-button>下载</el-button>
</template>
</el-popconfirm>
<el-button @click="saveExcelData">保存</el-button>
<el-popconfirm @confirm="resetExcel" title="确认重置么?">
<template #reference>
<el-button>重置</el-button>
</template>
</el-popconfirm>
<el-popconfirm @confirm="goToNodePage" title="返回通讯链路?">
<template #reference>
<el-icon size="22" style="cursor: pointer"><RefreshLeft /></el-icon>
</template>
</el-popconfirm>
</div>
</div>
</template>
<template #mainMain>
<div class="main" v-loading="hasLoading">
<div v-show="showTips" class="tips" :style="{ transform: `translate(${tipsPos.top},${tipsPos.left})` }">
<ul>
<li v-for="item in tipList" key="item">{{ item }}</li>
</ul>
</div>
<div ref="container" class="univer-container" />
</div>
</template>
</Container>
<el-dialog v-model="showCorrelationPoint" title="关联测点" @close="closecorrectionDevice">
<el-row>
<el-col :span="12">
<el-button @click="addCorrectionDevice" class="btnStyle">添加设备</el-button>
</el-col>
<el-col :span="12">
<el-popconfirm @confirm="clearCorrectionDevice" title="确认清空么?">
<template #reference>
<el-button class="btnStyle">清空</el-button>
</template>
</el-popconfirm>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<div class="treeMain">
<el-tree
ref="deviceTreeRef"
:data="deviceTreeData"
:props="repalceDeviceTreeKey"
node-key="id"
lazy
:load="loadDeviceTreeData"
show-checkbox
></el-tree>
</div>
</el-col>
<el-col :span="12">
<div class="treeMain">
<el-tree :data="correctionDevice" :props="repalceDeviceTreeKey" node-key="id" draggable :allow-drop="dropJudge">
<template #default="{ node, data }">
<div class="correctionTreeItem">
<span>{{ correctionDevice.findIndex((item: any) => item.id === node.key) + 1 + '、' + data.name }}</span>
<div class="rightItem">
<el-input v-if="data.isEdit" v-model="data.iotAddr" @keyup.enter="okEdit(data)" @blur="okEdit(data)"></el-input>
<el-tag v-else type="info" @click="editAttr(data)">{{ data.iotAddr }}</el-tag>
<el-popconfirm @confirm="delCorrectionDevice(node)" title="确认删除么?">
<template #reference>
<el-icon><Delete /></el-icon>
</template>
</el-popconfirm>
</div>
</div>
</template>
</el-tree>
</div>
</el-col>
</el-row>
<template #footer>
<el-button type="primary" @click="submitcorrectionDevice">提交</el-button>
<el-button @click="closecorrectionDevice">关闭</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import Container from '/@/components/container/index.vue'
import { equipQuery, equipType } from '/@/api/backend'
import { ElRow, ElCol, ElButton, ElTree, ElDialog, ElMessage, ElUpload, genFileId } from 'element-plus'
import type { UploadRequestOptions, UploadInstance, UploadProps, UploadRawFile } from 'element-plus'
import type { TreeInstance } from 'element-plus'
import { Delete, RefreshLeft } from '@element-plus/icons-vue'
import {
getMappingListReq,
saveMappingListReq,
getBindDeviceTreeReq,
bindDeviceMeasReq,
downloadMappingListReq,
uploadMappingListReq,
} from '/@/api/backend/node/request'
import { useRoute, useRouter } from 'vue-router'
import { onBeforeUnmount, onMounted, ref, reactive } from 'vue'
import '@univerjs/design/lib/index.css'
import '@univerjs/ui/lib/index.css'
import '@univerjs/docs-ui/lib/index.css'
import '@univerjs/sheets-ui/lib/index.css'
import '@univerjs/sheets-formula/lib/index.css'
import { Univer, UniverInstanceType, Tools, Workbook, LocaleType, IWorkbookData } from '@univerjs/core'
import { defaultTheme } from '@univerjs/design'
import { UniverFormulaEnginePlugin } from '@univerjs/engine-formula'
import { UniverRenderEnginePlugin } from '@univerjs/engine-render'
import { UniverUIPlugin } from '@univerjs/ui'
import { UniverDocsPlugin } from '@univerjs/docs'
import { UniverDocsUIPlugin } from '@univerjs/docs-ui'
import { UniverSheetsPlugin } from '@univerjs/sheets'
import { UniverSheetsFormulaPlugin } from '@univerjs/sheets-formula'
import { UniverSheetsUIPlugin } from '@univerjs/sheets-ui'
import DesignZhCN from '@univerjs/design/locale/zh-CN'
import UIZhCN from '@univerjs/ui/locale/zh-CN'
import DocsUIZhCN from '@univerjs/docs-ui/locale/zh-CN'
import SheetsZhCN from '@univerjs/sheets/locale/zh-CN'
import SheetsUIZhCN from '@univerjs/sheets-ui/locale/zh-CN'
import { FUniver } from '@univerjs/facade'
import { excelDefaultConfig, createWookbookData, createUpLoadExcelData, createSheetData, setExcelNameToLinkId } from './utils'
import { encrypt_aes, generateRandomNumber } from '/@/utils/crypto'
const route = useRoute()
const router = useRouter()
const hasLoading = ref(true)
const univerRef = ref<Univer | null>(null)
const workbook = ref<Workbook | null>(null)
const container = ref<HTMLElement | null>(null)
let univerAPI: any = null
//#region
// const commandWhiteList = [
// 'ui.operation.open-find-dialog',
// 'sheet.command.set-scroll-relative',
// 'sheet.operation.set-scroll',
// 'ui.operation.go-to-next-match',
// 'sheet.command.scroll-to-cell',
// 'sheet.command.scroll-view',
// 'formula.mutation.set-formula-calculation-notification',
// 'formula.mutation.set-formula-data',
// 'formula.mutation.set-other-formula',
// 'sheet.operation.set-activate-cell-edit',
// 'formula-ui.operation.help-function',
// 'formula.mutation.set-formula-calculation-start',
// 'sheet.mutation.data-validation-formula-mark-dirty',
// 'formula-ui.operation.search-function',
// 'formula.mutation.set-array-formula-data',
// 'formula.mutation.set-formula-calculation-result',
// 'doc.operation.set-selections',
// 'ui.operation.open-replace-dialog',
// 'sheet.operation.set-worksheet-active',
// 'sheet.operation.set-selections',
// ]
//#endregion
const init = async () => {
const reqSheetData = await getMappingList()
const sheetData = createSheetData(reqSheetData, 12)
const data = createWookbookData(route.query.protocol as any, route.query.id as string, sheetData)
initExcel(data)
}
const initExcel = (data = {}) => {
const univer = new Univer({
theme: defaultTheme,
locale: LocaleType.ZH_CN,
locales: {
[LocaleType.ZH_CN]: Tools.deepMerge(SheetsZhCN, DocsUIZhCN, SheetsUIZhCN, UIZhCN, DesignZhCN),
},
})
univerRef.value = univer
// core plugins
univer.registerPlugin(UniverRenderEnginePlugin)
univer.registerPlugin(UniverFormulaEnginePlugin)
univer.registerPlugin(UniverUIPlugin, {
container: container.value!,
})
// doc plugins
univer.registerPlugin(UniverDocsPlugin, {
hasScroll: false,
})
univer.registerPlugin(UniverDocsUIPlugin)
// sheet plugins
univer.registerPlugin(UniverSheetsPlugin)
univer.registerPlugin(UniverSheetsUIPlugin)
univer.registerPlugin(UniverSheetsFormulaPlugin)
// create workbook instance
workbook.value = univer.createUnit<IWorkbookData, Workbook>(UniverInstanceType.UNIVER_SHEET, data)
univerAPI = FUniver.newAPI(univer)
univerAPI.getSheetHooks().onCellPointerOver((cell: any) => {
//
if (cell?.location.row === 0 && cell?.location.col > 1) {
const { row, col, subUnitId } = cell.location
const typeId = subUnitId.slice(6)
const index = `R${row}C${col}`
tipList.value = excelDefaultConfig[route.query.protocol as any][typeId]?.[index] ?? []
if (tipList.value.length) {
showTips.value = true
} else {
showTips.value = false
}
tipsPos.top = cell.position.startX + 'px'
tipsPos.left = cell.position.startY + 90 + 'px'
} else {
showTips.value = false
}
})
hasLoading.value = false
}
/**
* Destroy univer instance and workbook instance
*/
const destroyUniver = () => {
return new Promise((resolve) => {
const result = univerAPI.disposeUnit('workbook-01')
univerRef.value = null
workbook.value = null
resolve(result)
})
}
/**
* Get workbook data
*/
const getData = () => {
if (!workbook.value) {
throw new Error('Workbook is not initialized')
}
return workbook.value.save()
}
const showCorrelationPoint = ref(false)
const openCorrectionPoint = () => {
getBindDeviceTree()
showCorrelationPoint.value = true
}
const deviceTreeRef = ref<TreeInstance>()
const deviceTreeData = ref([])
const repalceDeviceTreeKey = {
label: 'name',
isLeaf: 'isLeaf',
}
const getTreeDataType = () => {
equipType().then((res) => {
deviceTreeData.value = res.data.map((item: any) => {
return {
name: item.equipmentTypeName,
id: item.equipmentTypeId,
isType: true,
}
})
})
}
const loadDeviceTreeData = (node: any, resolve: any) => {
if (node.level === 0) {
return resolve(deviceTreeData.value)
}
equipQuery({ pageSize: 100, pageNum: 1, objectType: node.key }).then((res: any) => {
const data = res.rows.map((item: any) => {
return {
...item,
isLeaf: true,
}
})
return resolve(data)
})
}
const correctionDevice = ref<any[]>([])
const addCorrectionDevice = () => {
const nodeList = deviceTreeRef.value!.getCheckedNodes()
const data: any = []
nodeList.forEach((item) => {
if (!item.isType) {
const exist = correctionDevice.value.find((Correction) => Correction.id == item.id)
if (!exist) {
data.push(item)
}
}
})
correctionDevice.value = [...correctionDevice.value, ...data]
}
const clearCorrectionDevice = () => {
correctionDevice.value = []
}
const delCorrectionDevice = (node: any) => {
deviceTreeRef.value!.remove(node)
}
const editAttr = (data: any) => {
data.isEdit = true
}
const okEdit = (data: any) => {
data.isEdit = false
}
const submitcorrectionDevice = () => {
const bindDeviceId = correctionDevice.value.map((item: any) => {
return {
equipmentId: item.id,
iotAddr: item.iotAddr,
}
})
bindDeviceMeasReq({ equipmentId: bindDeviceId, linkId: route.query.id }).then((res) => {
ElMessage.success('关联成功!')
closecorrectionDevice()
})
}
const closecorrectionDevice = () => {
correctionDevice.value = []
showCorrelationPoint.value = false
}
const dropJudge = (draggingNode: any, dropNode: any, type: any) => {
if (type === 'inner') {
return false
}
return true
}
const showTips = ref(false)
const tipList = ref<string[]>([])
const tipsPos = reactive({
top: '0',
left: '0',
})
const saveExcelData = () => {
const data = getData()
const val = createUpLoadExcelData(data)
console.log(val);
saveMappingList(val)
}
const getBindDeviceTree = () => {
getBindDeviceTreeReq({ linkId: route.query.id as any }).then((res) => {
if (res.data) {
correctionDevice.value = res.data.map((item: any) => {
return {
id: item.equipmentId,
name: item.equipmentName,
iotAddr: item.iotAddr,
}
})
}
})
}
const getMappingList = () => {
const asyncReqList: any = []
const type = [138, 139, 140, 146, 147]
type.forEach((item) => {
asyncReqList.push(
getMappingListReq({ linkId: route.query.id as any, type: item }).then((res) => {
return { [item]: res.data }
})
)
})
return Promise.all(asyncReqList).then((data) => {
let result = {}
data.forEach((item) => {
result = { ...result, ...item }
})
console.log(result);
return result
})
}
const saveMappingList = (data: any[]) => {
hasLoading.value = true
saveMappingListReq(data).then((res) => {
if (res.success) {
ElMessage.success('保存成功!')
resetExcel()
}
})
}
const uploadRef = ref<UploadInstance>()
const upload = (file: UploadRequestOptions) => {
const formData = new FormData()
formData.append('file', file.file)
const v = generateRandomNumber(16)
const id = encrypt_aes(route.query.id, v)
formData.append('id', id)
return uploadMappingListReq(formData, v).then((res) => {
if (res.success) {
hasLoading.value = true
ElMessage.success('上传成功!')
resetExcel()
} else {
ElMessage.error(res.msg ?? '上传失败!')
}
})
}
const handleExceed: UploadProps['onExceed'] = (files) => {
uploadRef.value!.clearFiles()
const file = files[0] as UploadRawFile
file.uid = genFileId()
uploadRef.value!.handleStart(file)
uploadRef.value!.submit()
}
const download = () => {
downloadMappingListReq({ linkId: route.query.id as any }).then((res: any) => {
const title = res.headers['content-disposition'].match(/(?<=filename\=).*\.json$/)?.[0] ?? 'imptabmapping.json'
const url = window.URL.createObjectURL(res.data)
const a = document.createElement('a')
a.href = url
a.download = title
document.body.appendChild(a)
a.click()
window.URL.revokeObjectURL(url)
document.body.removeChild(a)
})
}
const resetExcel = () => {
destroyUniver().then((status) => {
if (status) {
init()
} else {
setTimeout(() => {
init()
}, 1000)
}
})
}
const goToNodePage = () => {
// router.push({ path: route.query.prevPath as string })
router.go(-1)
}
onMounted(() => {
init()
getTreeDataType()
getBindDeviceTree()
})
onBeforeUnmount(() => {
destroyUniver()
})
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
.main {
position: relative;
width: 100%;
height: 100%;
.univer-container {
width: 100%;
height: 100%;
overflow: hidden;
}
.tips {
position: absolute;
top: 0;
left: 0;
background-color: #ccc;
max-width: 300px;
color: brown;
padding: 5px 5px 5px 23px;
border-radius: 5px;
z-index: 9999;
}
}
/* Also hide the menubar */
:global(.univer-menubar) {
display: none;
}
.correctionTreeItem {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding-right: 10px;
.rightItem {
display: flex;
justify-content: space-between;
align-items: center;
min-width: 42px;
.el-icon {
margin-left: 10px;
}
}
}
.btnStyle {
margin-bottom: 10px;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
height: 100%;
.el-button {
width: 88px;
height: 40px;
}
.rightOperate {
display: flex;
justify-content: space-between;
align-items: center;
width: 410px;
.el-button {
margin: 0;
}
}
}
</style>

View File

@ -0,0 +1,376 @@
import { LocaleType, BooleanNumber, SheetTypes } from '@univerjs/core'
export const excelDefaultConfig: any = {
12: {
//遥测138 ANALOG
138: {
name: '模拟量',
head: [
{
label: '功能码',
code: 'col1',
},
{
label: '数据类型',
code: 'col2',
},
{
label: '数据符号',
code: 'col3',
},
{
label: '寄存器地址',
code: 'col4',
},
],
R0C3: ['03', '04'],
R0C4: [
'0 - 32位浮点数(高位在第一个寄存器)',
'1 - 32位浮点数(高位在第二个寄存器)',
'2 - 16位归一化值',
'3 - 32位归一化值(高位在第一个寄存器)',
'4 - 32位归一化值(高位在第二个寄存器)',
'5 - 32位浮点数(小端系统模式)',
'6 - 32位BCD数据(*高位在第一个寄存器*)',
'7 - 32位BCD数据(*高位在第二个寄存器*)',
'8 - 16位BCD数据',
], // 数据类型的提示
R0C5: ['0 - 无符号', '1 - 有符号'], // 数据符号的提示
},
//遥控147 CONTROL
147: {
name: '遥控量',
head: [
{
label: '功能码',
code: 'col1',
},
{
label: '执行前需要预置',
code: 'col2',
},
{
label: '选择合寄存器',
code: 'col3',
},
{
label: '执行合寄存器',
code: 'col4',
},
{
label: '撤销合寄存器',
code: 'col5',
},
{
label: '合闸数值',
code: 'col6',
},
{
label: '选择分寄存器',
code: 'col7',
},
{
label: '执行分寄存器',
code: 'col8',
},
{
label: '撤销分寄存器',
code: 'col9',
},
{
label: '分闸数值',
code: 'col10',
},
],
R0C3: ['05', '15', '06', '16'],
R0C4: ['0 - 直接执行', '1 - 预置执行'],
},
//遥调146 SETPOINT
146: {
name: '遥调量',
head: [
{
label: '遥调类型',
code: 'col1',
},
{
label: '功能码',
code: 'col2',
},
{
label: '执行前需要预置',
code: 'col3',
},
{
label: '选择寄存器',
code: 'col4',
},
{
label: '执行寄存器',
code: 'col5',
},
{
label: '撤销寄存器',
code: 'col6',
},
],
R0C3: ['0 - 16位整型值', '1 - 32位值高位在第一个寄存器', '2 - 32位值高位在第二个寄存器'],
R0C4: ['06', '16'],
R0C5: ['0 - 直接执行', '1 - 预置执行'],
},
//遥脉139 ACCUMULATOR
139: {
name: '累计量',
head: [
{
label: '功能码',
code: 'col1',
},
{
label: '数据类型',
code: 'col2',
},
{
label: '寄存器地址',
code: 'col3',
},
],
R0C3: ['03', '04'],
R0C4: [
'0 - 16位无符号整型值',
'1 - 32位无符号整型值(高位在第一个寄存器)',
'2 - 32位有符号整型值(高位在第一个寄存器)',
'3 - 32位无符号整型值(高位在第二个寄存器)',
'4 - 32位有符号整型值(高位在第二个寄存器)',
'5 - 32位浮点数值(高位在第一个寄存器)',
'6 - 32位浮点数值(高位在第二个寄存器)',
'7 - 64位双精度值(AB CD EF GH)',
'8 - 64位双精度值(GH EF CD AB)',
'9 - 32位短浮点数值(小端模式)',
'10 - 32位BCD数据(*高位在第一个寄存器*)',
],
},
//遥信140 DISCRETE
140: {
name: '离散量',
head: [
{
label: '功能码',
code: 'col1',
},
{ label: '偏移量', code: 'col2' },
{
label: '寄存器',
code: 'col3',
},
],
R0C3: ['01', '02', '03', '04'],
},
},
}
const DEFAULT_WORKBOOK_DATA = {
id: 'workbook-01',
locale: LocaleType.ZH_CN,
name: 'universheet',
sheetOrder: ['sheet-138', 'sheet-139', 'sheet-140', 'sheet-146', 'sheet-147'],
appVersion: '3.0.0-alpha',
styles: {
1: {
vt: 2,
ht: 2,
},
2: {
vt: 2,
ht: 2,
bg: {
rgb: '#eceff7',
},
},
},
sheets: {},
}
/**
* excel标题行
* @param protocol
* @returns
*/
const createHeaderData = (protocol: string | number) => {
if (!protocol) return {}
const headerData: any = {}
//#region
Object.keys(excelDefaultConfig[protocol!]).forEach((item) => {
const dynamicData: any = {}
excelDefaultConfig[protocol!][item].head.forEach((head: any, index: number) => {
const key = index + 2
dynamicData[key] = {
v: head.label,
s: '1',
custom: head.code,
}
})
const headerItemData = {
0: {
0: {
v: '设备名称',
s: '1',
custom: 'equipmentName',
},
1: {
v: '属性名称',
s: '1',
custom: 'name',
},
...dynamicData,
},
}
headerData[item] = headerItemData
})
//#endregion
return headerData
}
/**
* excel名称为linkId
* @param id linkId
*/
export const setExcelNameToLinkId = (id: string) => {
DEFAULT_WORKBOOK_DATA.name = id
}
/**
* excel数据
* @param protocol
* @param data excel数据
* @returns
*/
export const createWookbookData = (protocol: number, linkId: string, data: any = {}) => {
const headerData = createHeaderData(protocol)
const sheetData: any = {}
//#region
Object.keys(headerData).forEach((item) => {
const rowLen = Object.keys(data[item]).length + 1
sheetData['sheet-' + item] = {
type: SheetTypes.GRID,
id: 'sheet-' + item,
cellData: {
...headerData[item],
...data[item],
},
name: excelDefaultConfig[protocol][item].name,
tabColor: 'green',
hidden: BooleanNumber.FALSE,
rowCount: rowLen,
columnCount: Object.keys(headerData[item][0]).length,
zoomRatio: 1,
scrollTop: 200,
scrollLeft: 100,
defaultColumnWidth: 120,
defaultRowHeight: 30,
status: 1,
showGridlines: 1,
hideRow: [],
hideColumn: [],
columnData: {
0: {
w: 300,
h: 0,
},
1: {
w: 300,
h: 0,
},
},
rowHeader: {
width: 46,
hidden: BooleanNumber.FALSE,
},
columnHeader: {
height: 20,
hidden: BooleanNumber.FALSE,
},
rightToLeft: BooleanNumber.FALSE,
}
})
//#endregion
DEFAULT_WORKBOOK_DATA.sheets = sheetData
DEFAULT_WORKBOOK_DATA.name = linkId
return DEFAULT_WORKBOOK_DATA
}
export const createUpLoadExcelData = (workbookData: any) => {
const sheets = workbookData.sheets
const data: any = []
Object.keys(sheets).forEach((item) => {
const sheetkeyMap: any = {}
const sheetKeys = Object.keys(sheets[item].cellData)
sheetKeys.forEach((key) => {
const sheetData: any = {}
const fieldKeys = Object.keys(sheets[item].cellData[key])
if (key === '0') {
fieldKeys.forEach((fieldKey) => {
const sheetKey = sheets[item].cellData[key][fieldKey].custom
sheetkeyMap[fieldKey] = sheetKey
})
} else {
let params: any = {}
const sheetKeyMapKeys = Object.keys(sheetkeyMap)
for (let fieldKey of sheetKeyMapKeys) {
if (fieldKey === '0') {
sheetData.equipmentId = sheets[item].cellData[key][fieldKey].custom.equipmentId
sheetData.linkId = workbookData.name
sheetData[sheetkeyMap[fieldKey]] = sheets[item].cellData[key][fieldKey]?.v ?? ''
sheetData.type = sheets[item].cellData[key][fieldKey].custom.type
sheetData.id = sheets[item].cellData[key][fieldKey].custom.id
continue
}
if (fieldKey === '1') {
sheetData[sheetkeyMap[fieldKey]] = sheets[item].cellData[key][fieldKey]?.v ?? ''
continue
}
params[sheetkeyMap[fieldKey]] = sheets[item].cellData[key][fieldKey]?.v ?? ''
}
sheetData.params = JSON.stringify(params)
data.push(sheetData)
}
})
})
return data
}
export const createSheetData = (data: any, protocol: string | number) => {
if (!protocol) return {}
const excelCellDataMap: any = {}
const headerData = createHeaderData(protocol)
const resultData: any = {}
Object.keys(headerData).forEach((item) => {
excelCellDataMap[item] = {}
Object.keys(headerData[item][0]).forEach((key) => {
excelCellDataMap[headerData[item][0][key].custom] = key
})
const result: any = {}
data[item].forEach((obj: any, index: number) => {
const params = obj.params && obj.params !== '' ? JSON.parse(obj.params) : {}
obj = { ...obj, ...params }
const row = index + 1
result[row] = {}
Object.keys(obj).forEach((field) => {
const col = excelCellDataMap[field]
if (col) {
let custom: any
if (col === '0') {
custom = {}
custom.equipmentId = obj.equipmentId
custom.type = item
custom.id = obj.id
}
result[row][col] = { v: obj[field], s: '1', custom }
}
})
})
resultData[item] = result
})
return resultData
}

File diff suppressed because one or more lines are too long