• 工作真是每天都在探索未知啊!

    一直想记录下来工作中的进步,但是八个月过去都不知道有什么好写的。但是最近的工作越来越有意思了,因为我从盲目接受的阶段到了主动探索和整理的阶段。2.26今天早起来公司突然就有了总结点什么的灵感,于是终于开始鼓起勇气满足了我沉睡很久的求知欲!

    2025.2.26

    我一直想把那些机械测试的东西理一理的,这次等到ld说起我才先做了一个治理方向,对大数据的东西有了新的了解,也终于知道了这些不同的任务和表的设计,但是我可能还是无法独立判断不同情况要用哪种处理方式。先记录下:

    大部分表用hive存,这比较直接,写建表sql。

    如果是从其他部门获取的表,从权限、分区、聚合的角度可能需要hive2hive

    如果数据要从批处理进阶到实时读写,就需要做hive2hbase

    如果数据还要更高的性能,就需要设计缓存,这时做hive2tair,由于hive和hbase都是基于hdfs存储的,所以二者转换可以直接使用数据协同,但是转tair需要数据格式的转换(在转之前可能还需要数据清洗调优来适应tair高性能要求),通过分布式计算框架spark实现。大概是这样:

    val hiveData = spark.sql("SELECT * FROM hive_database.hive_table")

    val processedData = hiveData.filter("some_column is not null")

    processedData.rdd.foreachPartition { partition =>

    val tairClient = new TairClient("tair_server_address", port)

    partition.foreach { row =>

    tairClient.put(row.getAs[String]("key"), row)

    }

    tairClient.close()

    }

    这里用的是scala语言(spark原生语言),看起来真的简洁。

    如果数据需要全文搜索、复杂查询、日志分析,此时需要hive2ES,es可以设置多种查询条件找到匹配复杂规则数据。

    如果数据需要以实时消息流推送给消费者,就可以hive2kafka,允许不同业务方实时处理。反之,也可以kafka2hive将其他业务方的信息转存到我们表里。这些数据移动的过程都属于etl,也就是将原始数据提取、转换、加载到新库。

    Flink用在消息发出后根据一些过滤条件决定要不要放进缓存。数据一流入,就可以立即决策,也可以动态改规则(扩展性好、精确、高容错)。

    算法聚簇生产任务也使用了spark,在原始过滤条件里继续灌入使相似度降低的分组算法,根据位置信息将数据划分为不同的簇,然后再更详细地排名等,决定哪些结果留在最终的情报库

    2025.2.28

    这两天联调前端接口费了一大番功夫,虽然之前已经开发过一些前端页面了,但做的都是与已有功能类似的,所以代码大部分都可以copy。这次我的页面做在其他的项目里,所以我遇到了一些问题。

    首先我需要直接从前端的开发环境访问到后端的测试环境,而不是我习惯使用的mock平台。问了我的mentor,她帮我在代码里找到一个配置代理的地方,简单来说我只需要把后端的url配在proxy里就好了,可是我要用的后端项目和这个前端工程其他部分对应的后端并不是一套,所以我要在不影响原有功能的前提下另配一个proxy,这时发现原来的proxy在env里设置了全局(所以其他axios.get都省略了那部分全局的路径)。于是我试了试直接get(http://192….),这会报cors的错误,甚至找到cors unblock的工具,没用。我又试了试在新代理里用pathRewrite忽略原代理,也不可行。最后,直接在新vue文件的created调方法之前定义了baseurl强行覆盖了全局的,就解决了。。。可真简单啊5555

    第二个坑的就是这个前端居然没有热更新的功能,我改了好几次配置,想不明白为什么一直不发请求,原来没有commit根本就不生效。。。。

    拿到后端数据后就顺利很多了。筛选框里的model是已选项,:options是选项,然后根据层级拿到后端的数据。如{ "data": { "orgIds": 88888}} axios.get(“”,{params:{必填参数}}).then(response=>{this.orgIds=response.data.orgIds})

    这样就顺利把后端返回按照前端规定格式展示啦!

    定义完选项以后调通了查询按钮,@click绑定一个方法,要展示的数据初始值定义的不对,明明是数字我写成count:’’,还有访问的层级不对(从ai里copy的,错了还要自己检查半天),以及用不用this.不清楚,在 Vue 模板中使用 {{ dataoverview.p2 }} 时,组件已经定好了。

    总之就是因为不熟悉,所以很多简单错误自己都不能马上解决,还有就是时间紧又被老板催,让我没耐心排查,事实证明ai排查问题的效率并不高。不过虽然浪费了一点时间,但是最后点击一下按钮,数据全部返回出来的一瞬间是特别开心的,我感觉现在已经非常熟悉这一套流程了,下次再有前端任务给我一定是很轻松的了(正好后面排了一个大项目的前端)😆。周末继续完成剩下的接口,把图表数据导入。

    2025.3.4

    继上次开发完第一个查询接口以后,又过了三天,我终于把这个页面所有功能做完了!我对这其中涉及到的一系列细节都非常陌生,所以一直在边查边做,一边还在不停检查纠正ai胡的言乱语🙂‍↕️,但是这个页面终于正常了!我学到了好多神奇而厉害的东西!我也终于可以暂时结束这段时间极度的焦虑了。

    周日来公司先完成了列表选项数据的导入,第一步至少是有数据了。原本抄的其他页面的分页是前端做的,这次是后端返回的,所以直接写这样一个方法获取就好了:

    handlePageChange(pageNum, pageSize) {

    this.currentPageNum = pageNum; // 更新当前页码

    this.currentPageSize = pageSize; // 更新每页大小

    this.fetchData(); // 重新请求数据

    },通过fetchData来获取分页信息。原来的分页在切换页面时也没有发起后端请求,所以第一页以后都没有数据。

    这里我的筛选项直接读了带分页的services接口,第二天来发现一个问题:后端的分页是必传的,因此我的所有选项只包括第一页的内容,所以叫后端补了一个区分于查询接口的选项接口给我。这个新接口有两个字段支持多选,但是我传的参数是这样:appkey[]=com1&appkey[]=com2,一开始我以为是appkey没有定义为数组,实际是Vue的数组参数默认会被序列化,解决办法是在构造参数时将数组转换为逗号分隔的字符串,只需要:appkey: this.selectedAppKey.join(‘,’)这么分隔就好了!这样请求中的appkey参数就是appkey=com1,com2。由于不熟悉分页的交互和vue的规则,ai只是在我给的前端分页方式的代码上大做文章,让我一直在错误的方向排查。

    然后完成了bar图设计,这里需要查询到叶子粒度的数据,所以拿到后端一串name后/分隔、并pop出最后一个名称:const departmentName = item.displayName.split('/').pop();这里有两种情况,展示部门的数据(返回data:1)/展示除了部门下各组的数据(返回data:多),第二种情况从data[1]开始遍历获取就好: for (let i = 1; i < response.data.length; i++) 。此外这个筛选项可以非常方便的加一些功能:clearable可以打个叉 filterable可以模糊选择 multiple可以多选;

    再做了变更记录查看功能,这需要通过row来绑定这个列表的主键@click="openDrawer(scope.row),第一次打开drawer没有记录是因为括号里scope.row没填,还有点就是接口获取的是[{},{}]这类型的数据时,请求要用map:this.changeRecords = response.data.map(record =>({Time: record.Time})),record就是当前遍历的元素,同时html如果获取多个结果也要像这么遍历展示:v-for="machine in scope.row.machines”,如果要根据不同返回做展示上的区分,可以在html直接获取后端元素,像这样

    :theme="machine.overseasTag === 1 ? 'red' : 'green’”(只有请求参数才需要定义在方法里!!!)

    最后就是前端请求post接口,一开始后端填了这个格式:x-www-form-urlencoded ,我不能通过简单query调用,查到需要创建一个URLSearchParams,再设置这样的请求头,无果,最后定位到可能是sso的问题。修改sso配置后,我们调整为query请求,此时依然报400,可能是我post格式不对,不可以用params传,也不可以直接在请求体传,然后用了${encodeURIComponent(row.appkey)}这个函数提前构造好url再发请求就可以了(避免字符冲突和确保安全),神奇。

    明天早点来,把最后一个堆叠图做好。✌️

    2025.3.5

    今天一来在本地起项目的时候发现疑似鉴权失败的问题,login接口报错401(只能自动登录),请求的clientid不是代码里配置的。然后找到了这个办法重新登录就好了:

    if (res.data.status == 401) {

    // 重定向到sso登入页,默认登出后再登录重定向到应用首页

    window.location.href = ssoWeb.getLoginUrl()

    }

    昨天其实已经把项目给ld看过了,但是有一个图的横坐标的信息太长无法完全展示,其实鼠标悬浮也可以看到,但是我太完美主义了,所以开始改这个barchart。首先我要在component里定义一个echarts的组件定义行列,这个页面也用了其他的linechart、piechart,我就照着这几个组件的方法结合echarts的示例图改,改了半天一点也没生效,问了我的mt才发现,这些组件虽定义了,但引用的统一是另一个库: 😓😓😓好气啊。然后我就去找mtdv的库,想省略定义直接使用,但是这个库只有柱状堆叠图,没有条形堆叠图,展示出的横坐标还是不完整的,我想将行列互换,但是组件库定义的行列格式不一样。我又想定义一个直接翻转的方法,但是也不成功,所以只好重新再回去写组件。

    所以这次首先要确保vue文件使用了我定义的组件!

    • 标签名称:在模板中使用时,Vue 会自动将 PascalCase(文件名) 转换为 kebab-case(短横线分隔命名法)

    其次是堆叠图的一些定义:[{'部门': 'A', 'P0服务数': 100, 'P1服务数': 200}]

    const series = columns.slice(1).map((col)代表取columns索引1后的元素生成数组(第0个相当于表头),stack: 'total’,标记堆叠组

    data: rows.map(row => row[col] || 0)挨个遍历rows中每一项的col值,就获得了A组的数据:100、200;

    因此rows、columns代表的并不是横纵坐标,从mtdv直接互换不行是因为他内部已经封装了XY轴。此处自己定义XY轴

    yAxis: {

    type: 'category',//1.显示分类项

    data: rows.map(row => row['部门'])//2.用同样的方法定义纵坐标(上一个是定义数值);

    },最后在引用的地方定义这个chartrow,然后chartrow.push({}),再this.ChartData.rows = chartrow;图表就可以拿到接口返回的数据啦!

    虽然一直在碰壁,但是还好终于解决了,还好这周我的领导们至少没有催我,让我有时间慢慢把这些东西搞清楚了。合代码的时候发现自己commit了173次,值得纪念!可喜可贺!很多问题我都是问ai的,但是如果自己不清楚这么写的逻辑,就根本不能筛选判断,直接使用也会出现各种问题,不过前端的这些细节也太多了,我尽量在每次做完都记录下一些皮毛,应该总有一天可以不用一直跟ai对话就完成吧!未来一段时间要开始忙情报和算法的一些事,也充满了挑战,那我就有更多东西可写了!

    2025.3.10

    今天要写测试用例+完成测试任务+把老板周五提的需求给改完,担心做不完所以8点就来公司了,事实证明我把一切都想复杂了,今天是很轻松的一天。今天解决了一个困惑我很久的问题。就是页面的级联选项预填的时候,我传不进文本的值,因为我把options定义为了级联id,所以参数只能是这样的:‘111/222/333’,截断以及映射名称的逻辑都写死在其他的方法里,定义了defaultValue还是会被options覆盖,options也只能传id否则刷不出对应数据。然后我向ai调整了我的描述方式:如何使默认文本是departmentName,但绑定的值依旧是selectedOptions。最后找到了这个办法:

    :display-render="label => departmentName || label.join(' / ‘)”既能显示一个值,也不用改变实际的option。在选项框绑定的事件上传selectedOptions:

    onChange(value, selectedOptions) {

    // 当选择改变时,更新显示文本

    if (selectedOptions && selectedOptions.length > 0) {

    this.departmentName = selectedOptions.map(o => o.label).join(' / ');

    } else {

    this.departmentName = '美团平台 / 地图服务部'; // 恢复默认显示

    }

    // 其他逻辑...

    },

    这样才能在选项框选了其他内容时清空默认值实时更新。整体来说,用一个假文本冒充了✌️