架构图的实现过程

news2024/11/19 11:22:09

项目需求架构图

实现代码

index.vue
<template>
    <!-- 外层div -->
    <div class="topu-container" :style="{ minWidth: `${functionDomainList.length * 330}px` }">
        <!-- 头部显示 -->
        <div class="topu-heard">
            <!-- 网关 -->
            <el-tooltip effect="dark" :content="`供应商:${gatewayObj.supplierName || ''}`" placement="top">
                <div class="topu-gateway" @click="handleNodeClick(gatewayObj)">
                    <span>{{ gatewayObj.ecuTypeCode || '' }}</span>
                </div>
            </el-tooltip>
            <!-- 域 -->
            <div class="topu-domain-list">
                <div class="topu-domain" v-for="(item, index) in functionDomainList" :key="index">{{ item }}</div>
            </div>
            <el-checkbox @click.stop.native="() => { }" @change="$event => handleChange($event, gatewayObj)"
                         v-if="selection && gatewayObj.logicalEcuAddressHex && gatewayObj.status != 3"></el-checkbox>
        </div>
        <!-- ECU树结构 -->
        <div class="topu-body">
            <!-- 获取指定域下的ECU节点 -->
            <div class="ecu-tree" v-for="(domain, index) in functionDomainList" :key="index">
                <div>
                    <template v-for="item in getNodeTree(domain)">
                        <!-- 存在下属节点 -->
                        <EcuNodeTree v-if="item.children && item.children.length > 0" :node="item" :selection="selection"
                                     :busType="busType" @change="handleChange" @click="handleNodeClick"
                                     :key="`node-tree-${item.id}`" />
                        <!-- 不存在下属节点 -->
                        <el-tooltip v-else :key="`node-${item.id}`" effect="dark"
                                    :content="`供应商:${item.supplierName || ''}`" placement="top">
                            <div class="ecu-node"
                                 :class="[backgroundMap[item.status], getBusTypeColor(item)]"
                                 @click="handleNodeClick(item)">
                                <span>{{ item.ecuTypeCode || '' }}</span>
                                <el-checkbox @click.stop.native="() => { }" @change="$event => handleChange($event, item)"
                                             v-if="selection && item.logicalEcuAddressHex && item.status != 3"></el-checkbox>
                            </div>
                        </el-tooltip>
                    </template>
                </div>
                <!-- 以太网总线类型存在-横线 -->
                <template v-for="key in getBusEthernetIndexList(getNodeTree(domain))">
                    <div class="ethernet-node" :style="{ top: `${getBusEthernetXTop(key)}px` }">{{ key }}</div>
                </template>

                <!-- Ethernet需要单独右侧一条线 -->
                <div class="bus-ethernet" :style="{ height: `${getBusEthernetHeight(getNodeTree(domain))}px` }"></div>
            </div>
        </div>
        <!-- 尾部显示 -->
        <div class="topu-footer">
            <div class="bus-legend">
                <div class="bus-item" v-for="key in Object.keys(busColos)">
                    <div class="bus-line" :class="busColos[key]"></div>
                    <div class="ml-sm">{{ key }}</div>
                </div>
            </div>
            <div class="status-legend">
                <div class="legend-item" v-for="item in legendList">
                    <div class="legend-square" :class="item.color"></div>
                    <div>{{ item.text }}</div>
                </div>
            </div>
        </div>
    </div>
</template>
<script>
    import EcuNodeTree from './ecuNode.vue'
    import { arr2tree } from 'utils'
    import { apiQueryBusPage } from 'api/CarManage/CarPartManage';

    export default {
        components: { EcuNodeTree },
        props: {
            // 总线类型颜色
            busColos: {
                type: Object,
                default: () => {
                    return {
                        CAN: 'can',
                        CANFD: 'canfd',
                        Ethernet: 'ethernet',
                        LIN: 'lin',
                        KLIN: 'klin',
                        Other: 'other'
                    }
                }
            },
            legendList: {
                type: Array,
                default: () => {
                    return [
                        { value: 3, color: 'yellow', text: 'ECU无诊断数据' },
                        { value: 2, color: 'red', text: 'ECU存在故障' },
                        { value: 1, color: 'green', text: 'ECU不存在故障' },
                        { value: 4, color: 'gray', text: 'ECU无通讯' }
                    ]
                }
            },
            // 节点信息
            node: {
                type: Array,
                default: () => {
                    return []
                }
            },
            // 域
            functionDomainList: {
                type: Array,
                default: () => {
                    return []
                }
            },
            // node背景色标识
            backgroundMap: {
                type: Object,
                default: () => {
                    return {
                        0: '',
                        1: 'green',
                        2: 'red',
                        3: 'yellow',
                        4: 'gray',
                        5: 'gray'
                    }
                }
            },
            // 是否可选
            selection: {
                type: Boolean,
                default: false
            }
        },
        data () {
            return {
                busType: {},
                // 选中项
                selections: []
            }
        },
        computed: {
            // 获取网关信息
            gatewayObj () {
                // 不存在父节点
                return this.node.find(el => !el.parentId)
            },
            // 节点转换为树结构
            ecuList () {
                const list = this.node.filter(el => el.parentId)
                return arr2tree(list)
            }
        },
        created () {
            this.getBusType()
        },
        methods: {
            /**
             * 获取指定域下的ECU节点
             * @param {*} funcDomainCode 域名标识
             */
            getNodeTree (funcDomainCode) {
                return this.ecuList.filter(el => el.funcDomainCode == funcDomainCode)
            },
            /**
             * 递归的方式获取指定域下的ECU节点中存在ethernet总线时的位置计算高度
             * @param {*} nodelist 域下的节点
             * @param {*} nodeLeveIndex 当前节点位置 位置从1计算不分层级
             * @param {*} nodeIndex[] 存在ethernet总线时的节点位置
             */
            getBusEthernet (nodelist, nodeLeveIndex = 0, nodeIndex = []) {
                nodelist.forEach(el => {
                    // 当前节点位置默认位置
                    nodeLeveIndex += 1
                    // 判断是否存在子节点
                    if (el?.children?.length > 0) {
                        this.getBusEthernet(el.children, nodeLeveIndex, nodeIndex)
                    } else {
                        // 存在Ethernet总线时,存入
                        if (this.hasEthernet(el)) {
                            nodeIndex.push(nodeLeveIndex)
                        }
                    }
                });
                return nodeIndex
            },
            // 获取以太网总线类型总长度 - y轴
            getBusEthernetHeight (nodelist) {
                const nodeList = this.getBusEthernet(nodelist, 0, [])
                const [ lastIndex ] = [ ...nodeList ].reverse()
                return lastIndex ? ((lastIndex - 1) * 57 + 35) : 0
            },
            // 获取以太网总线类型 - x轴
            getBusEthernetIndexList (nodelist) {
                return this.getBusEthernet(nodelist, 0, []) || []
            },
            // 计算以太网总线类型 - x轴Top值
            getBusEthernetXTop (index) {
                return (index - 1) * 57 + 35
            },
            /**
             * 获取总线类型颜色汇总
             * @param {*} param0 当前几点总线类型
             */
            getBusTypeColor ({ busType }) {
                const colors = busType.split(',').map(el => {
                    return this.busColos[this.busType[Number(el)]] || 'other'
                })
                return colors
            },
            // 是否存在Ethernet 总线
            hasEthernet ({ busType }) {
                const typeList = busType.split(',').map(el => {
                    return this.busType[Number(el)]
                })
                const index = typeList.findIndex(el => el == 'Ethernet')
                return index != -1
            },
            // 获取总线类型
            async getBusType () {
                const { code, data, msg } = await this.$ajax(apiQueryBusPage, { pageSize: 200, pageNumber: 1 })
                if (code === this.$OK) {
                    this.busType = {
                        ...Object.fromEntries(data.list.map(el => [ el.id, el.busType ]))
                    }
                } else {
                    this.$message.error(msg)
                }
            },
            /**
             * 多选框选择事件
             * @param {*} val 选中结果
             * @param {*} node 节点
             */
            handleChange (val, node) {
                if (val) {
                    this.selections.push(node)
                } else {
                    const index = this.selections.findIndex(el => el.id == node.id)
                    this.selections.splice(index, 1)
                }
                this.$emit('check', this.selections)
            },
            // 获取选中项
            getChecked () {
                return this.selections
            },
            // node点击事件
            handleNodeClick (item) {
                this.$emit('click', item)
            }
        }
    }
</script>
<style lang="scss" scoped>
@import "../ecuTopu.scss";
</style>
子节点代码-ecuNode.vue
<template>
    <div class="ecu-tree-node">
        <el-tooltip effect="dark" :content="`供应商:${node.supplierName || ''}`" placement="top">
            <div class="ecu-sub-node" :class="[backgroundMap[node.status], getBusTypeColor(node)]"
                 @click="$emit('handleNodeClick', node)">
                <span>{{ node.ecuTypeCode || '' }}</span>
                <el-checkbox @click.stop.native="() => { }" @change="$event => emit('change', $event, node)"
                             v-if="selection && node.logicalEcuAddressHex && node.status != 3"></el-checkbox>
            </div>
        </el-tooltip>
        <div class="ecu-tree">
            <template v-for="item in node.children">
                <EcuNodeTree v-if="item.children && item.children.length > 0" :node="item" :selection="selection"
                             :busType="busType" @change="$event => $emit('change', $event)"
                             @click="$event => $emit('click', $event)" />
                <el-tooltip v-else effect="dark" :content="`供应商:${item.supplierName || ''}`" placement="top">
                    <div class="ecu-node" :class="[backgroundMap[item.status], getBusTypeColor(item)]"
                         @click="$emit('click', item)">
                        <span>{{ item.ecuTypeCode || '' }}</span>
                        <el-checkbox @click.stop.native="() => { }" @change="$event => $emit('change', $event, item)"
                                     v-if="selection && item.logicalEcuAddressHex && item.status != 3"></el-checkbox>
                    </div>
                </el-tooltip>
            </template>

        </div>
    </div>
</template>

<script>
    export default {
        name: 'EcuNodeTree',
        props: {
            node: {
                type: Object,
                default: () => { }
            },
            busType: {
                type: Object,
                default: () => { }
            },
            // 总线类型颜色
            busColos: {
                type: Object,
                default: () => {
                    return {
                        CAN: 'can',
                        CANFD: 'canfd',
                        Ethernet: 'ethernet',
                        LIN: 'lin',
                        KLIN: 'klin',
                        Other: 'other'
                    }
                }
            },
            backgroundMap: {
                type: Object,
                default: () => {
                    return {
                        0: '',
                        1: 'green',
                        2: 'red',
                        3: 'yellow',
                        4: 'gray',
                        5: 'gray'
                    }
                }
            },
            // 是否可选
            selection: {
                type: Boolean,
                default: false
            }
        },
        methods: {
            /**
             * 获取总线类型颜色汇总
             * @param {*} param0 当前几点总线类型
             */
            getBusTypeColor ({ busType }) {
                const colors = busType.split(',').map(el => {
                    return this.busColos[this.busType[Number(el)]] || 'other'
                })
                return colors
            },
            // 是否存在Ethernet 总线
            hasEthernet ({ busType }) {
                const typeList = busType.split(',').map(el => {
                    return this.busType[Number(el)]
                })
                const index = typeList.findIndex(el => el == 'Ethernet')
                return index != -1
            }
        }
    }
</script>

<style lang="scss" scoped>
@import "../../style/ecuTopu.scss";
</style>
CSS部分
.topu-container {
    --node-height: '40px';
    position: relative;
    display: flex;
    flex-direction: column;
    height: 100%;
    width: 100%;
    background-color: #fff;
    padding: 20px;
    overflow-x: auto;

    .topu-heard {
        position: relative;
        display: flex;
        flex-direction: column;
        border-radius: 4px;
        padding: 0 20px;
        border: 1px solid #DCDFE6;
        box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.01);
        background: #EBECF0;

        .topu-gateway {
            position: relative;
            text-align: center;
            height: 42px;
            line-height: 42px;
            font-weight: bold;
        }

        .topu-domain-list {
            display: flex;
            flex-direction: row;
            justify-content: space-between;

            .topu-domain {
                height: 42px;
                line-height: 42px;
                min-width: 300px;
                flex: 1;
            }
        }

        .el-checkbox {
            position: absolute;
            right: 10px;
            top: 50%;
            transform: translateY(-50%);
        }
    }

    .topu-body {
        position: relative;
        display: flex;
        flex: 1;
        justify-content: space-between;
        overflow-y: auto;

        .ecu-tree {
            position: relative;
            width: 300px;
            margin-left: 40px;
            height: 100%;

            .ecu-sub-node,
            .ecu-node {
                position: relative;
                width: 200px;
                height: var(--node-height);
                line-height: 40px;
                margin-top: 15px;
                padding: 0 20px;
                box-sizing: border-box;
                border-radius: 4px;
                background: #EBECF0;
                border: 1px solid #DCDFE6;
                z-index: 2;

                .el-checkbox {
                    position: absolute;
                    right: 10px;
                    top: -3px;
                }
            }

            .bus-ethernet {
                position: absolute;
                top: 0;
                right: 30px;
                width: 1.5px;
                background: #F154B1;
            }
            .ethernet-node{
                // tree节点margin-left:40px 
                // ethernetY轴 right: 30px 
                width: calc(100% - 70px);
                height: 1.5px;
                left: 40px;
                position: absolute;
                background: #F154B1;
            }
        }
    }

    .topu-footer {
        display: flex;
        justify-content: space-between;
        padding: 0 30px;
        height: 40px;
        align-items: end;

        .bus-legend {
            display: flex;

            .bus-item {
                display: flex;
                align-items: center;
                margin-right: 20px;

                .bus-line {
                    width: 20px;
                    height: 3px;
                }
            }
        }

        .status-legend {
            display: flex;
            justify-content: flex-end;

            .legend-item {
                display: flex;
                flex-direction: row;
                align-items: center;
                font-size: 12px;
                margin-right: 20px;

                .legend-square {
                    width: 15px;
                    height: 15px;
                    margin-right: 5px;
                }
            }
        }
    }
}

.ecu-node {

    &::before {
        position: absolute;
        content: '';
        width: 3px;
        height: 57px;
        left: -21px;
        top: -16px;
        transform: scale(0.5, 1);
        background-color: #1989FA;
    }

    &:last-of-type {
        &::before {
            height: 38px !important;
        }
    }

    &::after {
        position: absolute;
        content: '';
        width: 20px;
        height: 3px;
        left: -21px;
        top: 20px;
        transform: scale(1, 0.5);
    }
}

.ecu-tree-node {
    position: relative;

    .ecu-node {
        width: 160px !important;
    }

    &::before {
        position: absolute;
        content: '';
        width: 3px;
        height: calc(100% + 50px);
        left: -20.2px;
        top: -16px;
        transform: scale(0.5, 1);
        background-color: #1989FA;
    }

    &:last-of-type {
        &::before {
            height: 55px;
            top: -32px;
        }
    }
}

.ecu-tree-node {
    .ecu-tree-node {
        &::before {
            position: absolute;
            content: '';
            width: 3px;
            height: calc(100% + 70px);
            left: -21px;
            top: -16px;
            transform: scale(0.5, 1);
            background-color: #1989FA;
        }
    }
}

.ecu-sub-node {
    &::after {
        position: absolute;
        content: '';
        width: 20px;
        height: 3px;
        left: -21px;
        top: 20px;
        transform: scale(1, 0.5);
        background-color: #1989FA;
    }
}

.can {
    background: #F56C6C;

    &::after {
        background-color: #F56C6C;
    }
}

.canfd {
    background: #EA7232;

    &::after {
        background-color: #EA7232;
    }
}

.ethernet {
    background: #F154B1;
}

.lin {
    background: #67C23A;

    &::after {
        background-color: #67C23A;
    }
}

.klin {
    background: #48B1DB;

    &::after {
        background-color: #48B1DB;
    }
}

.other {
    background: #8C64D0;

    &::after {
        background-color: #8C64D0;
    }
}

.green {
    background: #67C23A !important;
}

.yellow {
    background: #E6A23C !important;
}

.red {
    background: #F56C6C !important;
}

.gray {
    background: #C0C4CC !important;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/699647.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue3高德地图点击标点

1.首先如果没有key的话需要在高德开发平台申请key。 2.安装 npm i amap/amap-jsapi-loader --save cnpm i amap/amap-jsapi-loader --save3.容器&#xff1a; <template><div><div class"info"><h4>获取地图级别与中心点坐标</h4>&l…

git常用命令之Cherry-pick

8. Cherry-pick 8.1 基本用法 命令作用延展阅读git cherry-pick 125a1d将提交125a1d应用于当前分支. 在当前分支会产生一个新的提交.链接git cherry-pick bugfix将分支bugfix应用于当前分支. 在当前分支会产生一个新的提交. 场景1&#xff1a;提交125a1d应用到master分支 命…

玖章算术与百度智能云达成合作,「NineData SQL 开发」成为百度智能云主推的数据库工具

2023 年 6 月 19 日&#xff0c;玖章算术&#xff08;浙江&#xff09;科技有限公司旗下的多云数据管理平台 NineData 正式入驻百度智能云市场&#xff0c;双方的深度技术融合将为客户提供智能高效、安全可靠的数据库开发服务。通过适配百度智能云数据库&#xff0c;NineData 为…

计算机网络中的安全

计算机网络中的安全 1 什么是网络安全2 加密的方式——机密性2.1 对称密钥加密2.2 公开密钥加密 3 报文鉴别码——报文完整性4 数字签名——报文完整性、端点鉴别4.1 数字签名技术的基础4.2 公钥认证 5 案例——设计安全电子邮件系统 《计算机网络—自顶向下方法》&#xff08;…

Postman中读取外部文件

目录 前言&#xff1a; 一、postman中读取外部文件的格式 二、Postman中如何导入文件 三、在Postman读取导入的数据文件 前言&#xff1a; 在Postman中&#xff0c;您可以使用"数据文件"功能来读取外部文件&#xff0c;如CSV、JSON或Excel文件。这使得在测试中使用…

如何应用Nginx Rewrit实现网页跳转

目录 一、Nginx Rewrite 二、Rewrite功能 Rewrite跳转场景 Rewrite跳转实现 Nginx 跳转 pcre支持 重写模块 Rewrite实际场景 Rewrite命令/语法格式 flag标记说明 location分类 location优先级 rewrite和location相比 三、跳转案例 实现域名跳转 第一步 修改指…

一文详解gRPC框架

目录 RPC框架简介 简介 各种序列化协议优缺点 gRPC调用模式 gRPC跟ProtocolBuffers的关系 ProtocolBuffers协议 gRPC桩代码生成 gRPC线程模型 gRPC分层 gRPC开发经验 官网及快速开始 常见状态码 适用场景 适用 不适用 手写简易RPC框架 Dubbo学习笔记 一文详解…

【python】数据表转csv

文章目录 1 基本结构1.1 数据1.2 数据结构 2 代码3 tip 1 基本结构 1.1 数据 1.2 数据结构 2 代码 代码&#xff1a; import mysql.connector import csvdef getPerson():# 数据库初始化cnx mysql.connector.connect(userroot, passwordroot, databasetest)cursor cnx.cur…

IDEA启动tomcat控制台中文乱码问题

IntelliJ IDEA是很多程序员必备且在业界被公认为最好的Java开发工具&#xff0c;有很多小伙伴在安装完IDEA并且tomcat之后&#xff0c;启动tomcat会出现控制台中文乱码问题&#xff0c;如下图所示&#xff1a; 具体解决步骤&#xff1a; 一、修改当前 Web 项目 Tomcat Server…

SAP ALV批量修改列的数据

导语&#xff1a;最近在给ALV增加批量修改列的功能&#xff0c;需求是修改多列&#xff0c;以前经常自己画屏幕来实现&#xff0c;研究了一下&#xff0c;SAP有标准的函数&#xff0c;可以自动带出选择列的字段属性&#xff0c;搜索帮助等等&#xff0c;大大提高了便捷性。 函…

本地同步远程yum源,并保存到本地

1.修改本地/etc/yum.repos.d/内容为远程yum repo配置&#xff1b; # 1&#xff09;.备份原yum配置 mkdir -p /home/yum-bak && mv /etc/yum.repos.d/* /home/yum-bak/* # 2&#xff09;.修改目标yum配置 2.执行缓存&#xff0c;查看相关repoid是否正确 yum clean all …

QT学习笔记2--对象树

对象树 可以看到QWidet这几个类的父亲是QObject&#xff0c;在析构的时候是从下往上析构。 实例 创建类 验证的话&#xff0c;要先创建一个类&#xff0c;命名为pushbotton。 点击choose创建&#xff0c;类。 编写相关函数 构造函数 pushbotton::pushbotton(QWidget *pare…

华为云专家出品《深入理解边缘计算》电子书上线

华为开发者大会PaaS生态电子书推荐&#xff0c;助你成为了不起的开发者&#xff01; 什么是边缘计算&#xff1f;边缘计算的应用场景有哪些&#xff1f; 华为云出品《深入理解边缘计算》电子书上线 带你系统理解云、边、端协同的相关原理 了解开源项目的源码分析流程 学成能…

【Python】字符串格式化前世今生

▒ 目录 ▒ &#x1f6eb; 问题描述环境 1️⃣ 《%》方式格式化语法%后面的参数说明 2️⃣ str.format优点指定位置&#xff1a;参数可以不按顺序关键字参数列表索引对象数字格式化 3️⃣ f-string 语法语法示例格式化一个表达式转义符号格式化 datetime 对象 &#x1f6ec; 结…

C#传Bitmap到C++dll出现灰色图片的问题

如果直接将内存中的Bitmap 传给C,原图会失去颜色&#xff0c;如下&#xff1a; 代码如下&#xff1a; ImageCodecInfo jpgEncoder GetEncoder(ImageFormat.Jpeg);System.Drawing.Imaging.Encoder myEncoder System.Drawing.Imaging.Encoder.Quality;EncoderParameters myEncod…

给若依添加单元测试(二)

给若依添加单元测试 方案一&#xff08;简单&#xff09; 方案二&#xff08;异常困难但企业开发一般用这个&#xff09; 在 activity 子模块中添加单元测试 S1.在 src 目录下创建 test.java.MapperTests 文件 S2.将以下内容复制进去 import com.ruoyi.activity.Activity…

C#私有构造函数学习

私有构造函数是一种特殊的实例构造函数。 它通常用在只包含静态成员的类中。 如果类具有一个或多个私有构造函数而没有公共构造函数&#xff0c;则其他类&#xff08;除嵌套类外&#xff09;无法创建该类的实例。 如果类T只声明了私有实例构造函数&#xff0c;则在T的程序文本外…

java项目之留学生交流互动论坛网站ssm源码

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的留学生交流互动论坛网站。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 &#x1f495;&#x1f495;作者&#xf…

python编码中常见问题及解决方案

文章目录 1. 输入minVal和maxVal&#xff0c;将 minVal - maxVal 分成 N 等份&#xff0c;列表返回2. request 请求MP4视频URL时&#xff0c;如何获取视频大小3. 输出00&#xff0c;01&#xff0c;02或001&#xff0c;002&#xff0c;003等格式字符串 1. 输入minVal和maxVal&am…

UE5 Stride Warping Orientation Warping功能学习

在UE5的 Lyra Demo中&#xff0c;运用到了各类动画Warping&#xff08;动画扭曲&#xff09;技术&#xff0c;通过各类Warping节点在动画蓝图中的合理组织&#xff0c;可以有效的解决运动滑步问题&#xff0c;并为动画增添更多细节。 本文主要基于Animation Warping插件讲一下…