洪泽问题梳理总结

洪泽项目 是基于 qiankun 框架的微前端项目。主应用(portal),四个子应用:综合决策分析(turbo)、模型平台(model)、维护管理平台(smart)、知识平台。

1、前言

洪泽项目时间跨度大,轮到我接手的时候(8月底)项目已经开发进行了一年多了,加之需求反反复复的变化,且每次更改并无更改的文档记录(口述),所以增加了一定的开发难度;项目牵扯面广,多个系统间存在着相互依赖的关系,还涉及多个第三方的资源,如:飞度的三维,antv/x6故障树,数学公式;需求无规划,也没有版本控制迭代这一说,而这种现象貌似已经成了此项目中的常态......

  • 使用qiankun时,多个子应用调试问题

    通常的方式是将每个子项目作为一个独立的应用进行开发和调试。每个子项目都可以在本地启动,并通过修改主应用的配置,让主应用去加载本地正在运行的子应用,这样就可以对子应用进行调试了。这种方式的好处是,子应用与主应用解耦,可以独立进行开发和调试,不会相互影响。还有另一种方式就是使用npm-run-all这个工具,可以并行或者串行多个npm脚本。

  • 三维飞度的调试

    飞度调试有自己的快捷调试入口:启动飞度的客户端,会有对应的服务启动(10.218.108.163:8090);把IP地址复制到浏览器中(http://10.218.108.163:8090/samples/locale_zh/index.html);把 index 改为 main 进行回车就进入了快捷调试的界面。前端与飞度交互,一般都是通过操作API进行:每次启动客户端都会存在目前版本所对应的文档(http://10.218.108.163:8090/doc/api/)。飞度的调试注定是坎坷的:客户端操作可行性;部署所在机器的性能;更多API细节还得问飞度开发者。

2、问题列表

2.1 静态资源

三维中很常见的操作:打点(参考地图上坐标打点)。测试环境与开发环境中发现,点位图片消失不见!

问题分析及解决:

  1. 常见反应:资源本地?是否丢失或者路径不对?
  2. 查看代码定位,找到打点的方法(一般都是通过与三维API交互实现,tag.add())(截图)
  3. 浏览器回车,图片获取不到。地址为何获取不到图片?(IP为三维服务器,证明资源在部署三维的机器上)
  4. 三维机器上查找资源或者路径(三维安装很混乱,原先卸载过也不删除文件),后面总结出来了一个规律,可以按照以下的步骤查看路径下是否有文件(截图)
  5. 开发环境OK了,就开始定位测试环境,经过一系列排查操作后,测试环境对应的路径下资源也正常。(能咋办?该做的也都操作了,重启吧)没想到重启好了!!!
  6. 总结:静态资源的导入最好三维重启

2.2 CFD-水流(三维中操作二维)

需求很简单,就是CFD下需要展示水流的效果。1-5号机组与调水模拟的场景下,都存在CFD。洪泽工况有三种情况:发电、调水跟其他,1-5号机组下的CFD展示只能在调水的情况下点击,其余不能点击;调水模式很难遇到,一般是到11月份才会调水,所以调水模拟就产生了,调水模拟下水泵、机组、声纹、CFD都可以切换点击。

  • 快速切换水泵、机组、声纹,多切换几次,最后到CFD,就会看到所绘制的水流存在阴影
  • CFD下展示八个换能器,每次出现的时机都早于水流,正常的逻辑应该是在水流产生之后出现

问题分析及解决:

  1. 快速切换,前端的指令是实时的,但是调用三维接口,三维拉近视角的这个过程却是异步的。水流的绘制呢是用canvas实现的(大致原理:截图快照,把多余的内容转化为透明,相当于挖了一块),就是截图快照的时候有时候三维还停留在别的视角。(问题照片,此处省略。)

    核心:三维视角结束后,再绘制水流。

    (1)、调用视角方法的回调,查看文档支持回调,前端封装方法中也支持回调。但是尝试发现回调方法没生效(此刻版本5.3),故另辟途径。

    js 复制代码
    export const setCamera = (arr, flyTime, fn) => {
      const jsb = window.__g
      jsb && jsb.camera.set(arr, flyTime, fn)
    }

    (2)、三维中有切换完视角的回调方法,是系统层面的回调。全局维护两个变量,点击事件与完成回调后的事件,再对比两个变量是否一致。

    js 复制代码
    case 'CameraChanged':
      if (domId === 'screen-player1') {
        main_before_events.value = []
        main_events.value = []
      } else if (domId === 'screen-player2' && main_before_events.value && main_before_events.value.length) {
        const arr = main_events.value
        arr.push({
          ...event
        })
        main_events.value = arr
        console.log('CameraChanged 事件刚点击 main_before_events:', main_before_events.value)
        console.log('CameraChanged 事件完成后 main_events:', main_events.value)
      }
      break
      
    // 监听
    main_events(val) {
      console.log('watch newIndex main_events:', val)
      console.log('watch newIndex main_events_before_events:', this.main_before_events)
      // 相机位置切换成功的回调,是否渲染水流,应判断点击完水流出现的条件最终的视角,且当前页面的队列全部执行完成
      if (this.main_before_events && val.length && this.main_before_events.length === val.length) {
        console.log('watch newIndex main_events_before_events length ==:', this.main_before_events.length)
        this.isCameraDone = true
      }
    }

    (3)、前端调整调水模拟的入口。效果还是不够理想,还是会存在偶先的上述情况。故向上反馈,跟飞度三维那边协商就直接让三维搞水流,后续由于种种原因没有推进下去,希望前端这边还是能再思索别的优化方案。 (截图 对象执行focus()或相机执行set()/lookAt()/lookAtBBox()方法时触发)

    (4)、水泵机组声纹CFD切换也加入弹窗遮罩,限制用户频繁点击,规避上述问题产生,降低出现问题的概率。

    (5)、1108号,在书写这份文档梳理总结的时候,突然就对(1)中方法产生了浓厚兴趣,就想研究下为何回调会没生效。结果这次试验,竟然成功了,回调中有打印!!!被催的当时头脑一定在发热,要是当初第一次尝试成功,就没有后续很多繁琐的事情了...(不过此刻版本是从5.3升到5.4的,不知是否跟版本有关系,5.3版本确实存在很多问题)

    js 复制代码
      setCamera(VIEWPORT_MAP.xcj_cfd, 0, (done) => {
        console.log('8888888888888889999', done)
        setTimeout(() => {
          this.isCameraDone = true
        }, 1000)
      })
  2. CFD模式下,出现水流与换能器的点,绘制水流的过程需要经过一系列算法来实现,这就导致了水流还未绘制完成,换能器的八个点已经出现。(截图)

    (1)、核心:延迟换能器出现的时机。canvas完成事件回调?如何知道canvas绘制完成?设置固定时间延迟?

    (2)、折中办法:监听canvas的dom属性变化。经发现,绘制水流的时候,会给canvas上设置style属性,证明此时下一步就进入算法阶段了。(截图)

    js 复制代码
    Vue.directive('listen-attr', {
      inserted(el, binding) {
        var callback = function(mutationsList) {
          for (var mutation of mutationsList) {
            if (mutation.attributeName === 'done') {
              var disabled = el.getAttribute('done')
              binding.value(disabled)
            }
          }
        }
        // 创建一个观察器实例并开始监听
        var observer = new MutationObserver(callback)
        observer.observe(el, { attributes: true })
      }
    })
    
    <canvas id="flow_canvas" v-listen-attr="handleDisabledChange" class="video-container" />
    // 监听dom中属性,添加了style的属性证明水流绘制完成了
    handleDisabledChange(data) {
      if (data) {
        console.log('disabled属性的值变为:', data)
        this.$emit('change-canvas-status', true)
      }
    }

    change-canvas-status触发的方法再延迟1s,用于抵消canvas中计算的时间,故方法并不是很完美,万一计算很费时间...

2.3 故障树(antv/x6

故障树的生成是在知识平台,每次让调整修改下,口头禅:我们是做的统一平台,不能做成单独定制化的项目。导致这边只能各个角度思考解决方案,为了解决而解决。

  • 可视窗口放不下:你看人家UI,配置的树的节点跟UI一致,为啥人家就能一屏放下,这边就不行呢
  • 边界范围:这边最多配置多少行多少列,不会多出来的
  • 展示位置不对:标红异常的一列位置不对,不能在最左列,明显数据太假了...
  • 开始结束或者多余节点删除:原先是咱这边自己的后台中间拿到数据,把开始结束手动去除(嗯,是有些厉害的),后续只是又发现了:知识平台给过来的树节点,还会多一个这边不要的节点,这...
  • 下载PDF中包含的故障树,树的节点样式丢失

改动前的示例:(此处省略两张图片)

解决方案:

  1. 拓宽可视范围的宽高;一屏一定要放的下使用 graph.zoomToFit() 这个方法;数据量少会放大节点,数据量多会过度压缩节点(节点数量区分是否缩放?层级?是否能缩短连接线?); Dagre布局

  2. 边界问题,毕竟UI所画的是固定的一种情形,现实中是会存在多种场景的,数据量可能更大,产品项目层不考虑而开发不得不考虑,当然需求最后也没能确认后面可能存在的数据到底有多少(无形之中又是个坑?)。总归一句话,出了问题再看再思考解决方案

  3. 异常数据的位置不对,每个节点配置存在XY属性,然并没生效。

    • Dagre布局在作妖,作妖即除妖,干掉此布局的使用,万事大吉。
    • 事实证明并非如此简单,有的节点会四五个甚至更多完全重叠在一起,有的会相互遮挡一半,很明显XY的值有问题(知识平台:我们无法调XY的值;OS:......)。
    • 节点拖拽,拖拽完生成的节点信息能否导出,并且包含对应的XY信息呢?导出的信息再次保存覆盖知识平台的数据 graph.toJSON()
    • 保存导出的信息再次读取,前端节点会提示报错,并且再次渲染就不能拖拽及删除
    js 复制代码
    const old = this.graph.toJSON().cells || []
    // 利用 析构赋值 此方法去除掉component
    const newArray = old.map(item => {
    const { component, ...rest } = item
    return rest
    })
    console.log(newArray)
    const str = JSON.stringify(newArray)
  4. 多余节点的删除(示例),知识平台反馈说是多余的节点是结束的上一个节点,不会是中间节点(如果要是中间节点,那就得研究X6中节点如何连接了)

  5. 原先的下载是主要用 html2canvas 来实现的,后面涉及到故障树的下载是通过 dom-to-image 来实现的。(故障树有自己的导出图片,能否通过最后的拼凑实现最后效果?)

    • html2canvas 通过遍历DOM树,将每一个HTML元素转化为Canvas对象,并叠加到一起形成一张完整的图片或者PDF文件
    • dom-to-image 库可以帮你把dom节点转换为图片,它的核心原理就是利用 svg 的 foreignObject 标签能嵌入 html 的特性,然后通过img标签加载svg,最后再通过 canvas 绘制 img 实现导出

2.4 数学公式

需求很简单,就是让项目中能够展示数学公式,项目发布后也可以正常显示。

解决方案:

  1. 最简单又暴力的方式-图片

  2. 经过初步筛选,锁定了MathJax渲染工具,可以做到输入LaTeX,输出HTML,展示为数学公式

    • mathJax只要引入全局资源和全局配置,就能自动把全站的公式都识别出来(页面渲染好后,脚本开始执行,在网页中寻找符合条件的公式符号,比如被包裹在$中的内容,并把它编译
    • 引入依赖,不推荐用npm安装,说是有存在莫名的报错
    js 复制代码
    <script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML"></script>

    新建一个js文件(MathJax.js)

    js 复制代码
    let isMathjaxConfig = false // 用于标识是否配置
    // window.MathJax = MathJax;
    const initMathjaxConfig = () => {
      if (!window.MathJax) {
        return
      }
      window.MathJax.Hub.Config({
        showProcessingMessages: false, // 关闭js加载过程信息
        messageStyle: 'none', // 不显示信息
        jax: ['input/TeX', 'output/HTML-CSS'],
        tex2jax: {
          inlineMath: [['$', '$'], ['\\(', '\\)']], // 行内公式选择符
          displayMath: [['$$', '$$'], ['\\[', '\\]']], // 段内公式选择符
          skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code', 'a'] // 避开某些标签
        },
        'HTML-CSS': {
          availableFonts: ['STIX', 'TeX'], // 可选字体
          showMathMenu: false // 关闭右击菜单显示
        }
      })
      isMathjaxConfig = true // 配置完成,改为true
    }
    const MathQueue = function(elementId) {
      if (!window.MathJax) {
        return
      }
      window.MathJax.Hub.Queue(['Typeset', window.MathJax.Hub, document.getElementById(elementId)])
    }
    export default {
      isMathjaxConfig,
      initMathjaxConfig,
      MathQueue
    }

    多处地方使用,可以提取到mixins文件中

    js 复制代码
    import MathJax from '@/utils/MathJax'
    
    export default {
      created() {
        this.formatMath()
      },
      methods: {
        formatMath() {
          setTimeout(() => {
            this.$nextTick(function() {
              if (MathJax.isMathjaxConfig) { // 判断是否初始配置,若无则配置。
                MathJax.initMathjaxConfig()
              }
              MathJax.MathQueue()
            })
          }, 300)
        }
      }
    }

    在vue文件中直接写入LaTeX,就会自动识别展示为数学公式。

    js 复制代码
    <span v-html="formulaOne" />
    
    import math from '@/mixins/math'
    
    data() {
        return {
            formulaOne: `$$L = D \\times f_{s} \\times f_{w} \\times R_{w} $$`
        }
    }

    到此就算是成功了,在项目中也可以正常展示了。但洪泽项目是基于乾坤的微应用,洪泽会对全局变量window下的属性进行劫持转化,会添加一层proxy,即window.MathJax会变成window.proxy.MathJax。对MathJax.js文件进行改造?全局引入的依赖中又如何更改?

  3. 全局依赖的改造无从下手,再加上时间紧迫,转而寻找别的开发思路,换依赖!基于vue的 VaTex ,这种方式也比上一种使用更简单,最明显的是直接展示数学公式,而不需要像上面一种先展示一串字符串,在紧接着变化为数学公式。

    js 复制代码
    npm i vatex katex --save
    
    import { VueLatex } from 'vatex'
    components: {
       VueLatex
    }
    <vue-latex :expression="formula" :display-mode="false" :fontsize="14" />
    
    formula: `R_{w}=1 - {\\Delta L \\times  a_{i} \\over b_{1} - b_{0}}`

3、遗留的问题

  1. url每次回车对参数进行编码

    单个项目中路由中带参数多次刷新都正常;经过qiankun打开的项目路由带参数刷新就异常 截图

  2. qiankun切换项目,清除原先的所有请求?

4、总结

  • 开发过程中遇到坑,大多数人第一反应并不是翻文档(我自己也是),而是去搜索有没有人遇到类似问题。
  • 遇到棘手问题的可以及时沟通,多人不同的思路,也许其中一个建议就能解决燃眉之急。
相关推荐
小政爱学习!13 分钟前
封装axios、环境变量、api解耦、解决跨域、全局组件注入
开发语言·前端·javascript
魏大帅。18 分钟前
Axios 的 responseType 属性详解及 Blob 与 ArrayBuffer 解析
前端·javascript·ajax
花花鱼25 分钟前
vue3 基于element-plus进行的一个可拖动改变导航与内容区域大小的简单方法
前端·javascript·elementui
k093328 分钟前
sourceTree回滚版本到某次提交
开发语言·前端·javascript
EricWang13581 小时前
[OS] 项目三-2-proc.c: exit(int status)
服务器·c语言·前端
September_ning1 小时前
React.lazy() 懒加载
前端·react.js·前端框架
web行路人1 小时前
React中类组件和函数组件的理解和区别
前端·javascript·react.js·前端框架
超雄代码狂1 小时前
ajax关于axios库的运用小案例
前端·javascript·ajax
长弓三石1 小时前
鸿蒙网络编程系列44-仓颉版HttpRequest上传文件示例
前端·网络·华为·harmonyos·鸿蒙
小马哥编程2 小时前
【前端基础】CSS基础
前端·css