注册
环信即时通讯云

环信即时通讯云

单聊、群聊、聊天室...
环信开发文档

环信开发文档

Demo体验

Demo体验

场景Demo,开箱即用
RTE开发者社区

RTE开发者社区

汇聚音视频领域技术干货,分享行业资讯
技术讨论区

技术讨论区

技术交流、答疑
资源下载

资源下载

收集了海量宝藏开发资源
iOS Library

iOS Library

不需要辛辛苦苦的去找轮子, 这里都有
Android Library

Android Library

不需要辛辛苦苦的去找轮子, 这里都有

​遇事不决表情包先行,Soul APP揭示年轻人新社交礼仪

在快节奏的现代生活中,年轻人的线上社交方式正悄然发生着变化。当面对纷繁复杂的信息交流时,一句简单的“在吗”似乎已不足以表达他们丰富的情感与态度。于是,“遇事不决表情包先行”成为一种新的社交常态。Soul App发布的《Z世代线上社交礼仪报告》深刻洞察了这一趋势...
继续阅读 »

在快节奏的现代生活中,年轻人的线上社交方式正悄然发生着变化。当面对纷繁复杂的信息交流时,一句简单的“在吗”似乎已不足以表达他们丰富的情感与态度。于是,“遇事不决表情包先行”成为一种新的社交常态。

Soul App发布的《Z世代线上社交礼仪报告》深刻洞察了这一趋势。报告指出,表情包已成为Z世代线上沟通中不可或缺的一部分,其使用频率非常高,种类也非常丰富。同时,报告还揭示了包括长语音反感、文字讨好症在内的多种线上社交现象,勾勒出了当代年轻人独特的线上社交礼仪图景。

一、线上社交礼仪的兴起与进化

对于大部分Soul App的用户群体而言,使用表情包几乎成为线上交流的标配。《Z世代线上社交礼仪报告》基于Soul App的大量用户数据,对年轻人的线上社交习惯进行了剖析。

报告指出,表情包之所以在年轻人中如此受欢迎,是因为它能够快速、直观地传达情绪,弥补文字交流的不足。无论是开心、难过、愤怒还是尴尬,总有一款表情包能够精准表达年轻人的内心世界。这种趋势背后,是年轻人对个性化和多元化表达的追求。

相比之下,长语音则成为年轻人社交中的“雷区”。报告显示,超过70%的年轻人认为超过30秒的语音就算长语音,而长语音的高频轰炸更是令人难以忍受。这背后,反映的是年轻人对社交效率的重视以及对信息密度的追求。在快节奏的生活中,他们更倾向于通过简洁明了的文字或表情包进行交流,而非花费大量时间听取冗长的语音消息。

除了表情包和长语音外,报告还揭示了不同年龄段用户在称呼和回复速度上的偏好差异。在称呼方面,年轻人更倾向于使用亲昵但不油腻的称呼,如“哥哥”“姐姐”等,以拉近彼此的距离。而“大哥”“大姐”等称呼则因显得过于正式或老气而受到冷落。

在回复速度上,年轻人普遍期望对方能够在较短时间内回复消息,以体现尊重和重视。报告显示,超过半数的年轻人认为5分钟内回复消息是有礼貌的,而秒回更是被视为一种高度的社交礼仪。然而,在实际操作中,受到各种因素影响,年轻人往往难以做到秒回,这也导致了“意念回复”现象的存在。

二、Soul App如何提升线上社交体验

针对年轻人对表情包的热爱,Soul App通过算法推荐技术,为用户提供了个性化的表情包推荐服务。根据用户的聊天习惯、兴趣爱好以及情感状态等因素,Soul App能够精准地为用户推送符合其需求的表情包,帮助用户更好地表达自己的情感和态度。同时通过 Soul APP的“群聊派对”功能,年轻用户可以找到多元精彩群聊,其中就包括专门分享流行趣味表情包的群聊。这些表情包不仅形式多样,风格各异,而且紧跟时代潮流,总能在第一时间捕捉到年轻人的心声。

此外,Soul还依托其自研的AI技术,创新推出了“数字分身”功能。用户只需简单授权,平台即可根据聊天记录、发帖内容或自定义设置,为用户打造一个独一无二的数字分身。这个数字分身在形象、声音、文字风格等表征层,社交关系、长期记忆、人设信息等身份层,以及决策、观点、偏好等认知层上,均能实现对真人的复刻。“数字分身”的智能回复能力,能够为用户提供更加个性化的智能回复推荐,有效助力社交破冰,在遵循当代年轻人线上社交礼仪的同时,提升回复和交流的效率,帮助用户在Soul App上进行高质量、高效的互动。

三、定义新时代社交文化

作为社交网络平台,Soul App始终坚持以用户为中心的发展理念。通过深度洞察年轻人的社交需求和习惯变化,Soul App得以及时推出更符合他们口味的功能与内容。

例如,针对年轻人对新鲜感的追求,Soul App推出了“3D捏脸”创意玩法,让用户能够根据自己的喜好定制专属的虚拟形象。针对年轻人对社交效率的重视,Soul App不断优化消息推送机制,尽力保障用户能够及时收到重要信息。这些举措不仅提升了用户的社交体验,也进一步巩固了Soul App在年轻人心中的品牌形象。

同时,Soul App还通过一系列社交活动和功能设计,积极倡导健康、文明、友好的线上社交风尚。例如,通过推出社交规范,Soul App鼓励用户以更加积极、正面的态度参与线上社交活动。通过优化举报和封禁机制等措施,Soul App有效打击了网络欺凌和恶意攻击等不良行为。这些举措不仅顺应了年轻用户线上社交礼仪的发展趋势,还提升了Soul App的社区氛围和用户体验。

结语

在这个线上社交频繁的时代,“遇事不决表情包先行”已成为年轻人线上社交的新常态。而Soul App作为Z世代的聚集地和精神家园,始终坚持以用户为中心的发展理念,通过不断创新和优化产品功能与服务体验,为年轻人提供了一个更加自在、开放、友好的社交空间。在这个空间里,年轻人不仅能够找到志同道合的伙伴、分享彼此的兴趣爱好和生活点滴,更能够在互动交流中不断学习和成长、自在地享受属于自己的社交礼仪和文化。在对年轻社交潮流的引领和持续推动社交领域的创新方面,Soul App发挥着重要的作用。随着线上社交的发展和演进,Soul App也正为年轻人带来更加丰富多彩的社交体验和生活方式。

收起阅读 »

SkyWise Digital:助力国际品牌成功进军中国市场

伦敦,2025年1月8日 —— SkyWise Digital 天智数字营销正式成立,专注于为国际品牌提供定制化的市场进入策略和数字营销服务,帮助他们成功打入中国市场。作为一家集文化洞察、数据驱动与创新技术于一体的专业机构,SkyWise Digit...
继续阅读 »

伦敦,2025年1月8日 —— SkyWise Digital 天智数字营销正式成立,专注于为国际品牌提供定制化的市场进入策略和数字营销服务,帮助他们成功打入中国市场。作为一家集文化洞察、数据驱动与创新技术于一体的专业机构,SkyWise Digital 致力于帮助西方品牌解锁中国市场的巨大潜力。

专注中国市场:连接品牌与消费者

中国作为全球增长最快的消费市场之一,拥有庞大的中产阶级和独特的数字生态系统。SkyWise Digital 凭借其对中国消费者行为和文化的深刻理解,为西方品牌提供全面的市场解决方案,确保品牌信息能够精准触达目标受众。

“我们发现,许多国际品牌对进入中国市场充满兴趣,但由于文化差异和市场复杂性,往往面临诸多挑战。” SkyWise Digital创始人 戴彬 表示,“我们的使命是消除这些障碍,让品牌能够更轻松、更高效地接触中国消费者,实现业务增长。”

核心服务:帮助品牌解锁中国市场潜力

SkyWise Digital 的服务体系涵盖从战略到执行的各个环节,包括:

  • 市场进入策略:通过深入的市场调研和消费者洞察,为品牌制定量身定制的中国市场进入计划,降低风险并提高成功率。

  • 社交媒体营销:利用中国领先的社交平台(如微信、小红书、抖音)进行内容营销和广告投放,帮助品牌与消费者建立互动。

  • 品牌本地化:提供文化适配的品牌策略和设计服务,确保品牌形象符合中国市场的文化预期。

  • 公关与声誉管理:通过媒体关系管理和危机公关,帮助品牌提升在中国市场的知名度和影响力。

行业覆盖广泛,助力多元化发展

SkyWise Digital 为包括B2B,房地产、奢侈品、教育、酒店与旅游等多个行业的西方品牌提供服务,帮助他们吸引中国消费者,建立深度连接。无论是打入新兴市场的企业,还是希望巩固在中国市场地位的成熟品牌,SkyWise Digital 都能提供量身定制的解决方案。

愿景:成为品牌全球化的首选伙伴

SkyWise Digital 的愿景是通过智慧的策略和卓越的执行,帮助品牌在中国市场脱颖而出,实现长期成功。创始人 戴彬 表示:“中国市场不仅仅是一个增长机会,更是一个战略性市场。我们希望成为每个品牌在中国的成功桥梁。”


关于SkyWise Digital - London Based Chinese Marketing AgencySkyWise Digital 是一家总部位于伦敦的数字营销机构,专注于帮助国际品牌进入中国市场并实现业务增长。了解更多信息,请访问官方网站 http://www.skywisedigital.com
媒体合作及咨询,请联系:
contact@skywisedigital.com


收起阅读 »

人总得裸辞一次(🎉裸辞|离沪|进京|入职|恋爱|买房|2024)

2024马上就要过去了,本命年呀,这一年真的太快太快了,发生了很多事情,记录一下,多年以后或许能够看到有一点点记录就足够了。 还记得2023年跨年的时候来北京跨年的,2024就真的到了北京工作,这一年算是集中发生了很多事情,比23年22年都精彩一些。 有一些错...
继续阅读 »

2024马上就要过去了,本命年呀,这一年真的太快太快了,发生了很多事情,记录一下,多年以后或许能够看到有一点点记录就足够了。


还记得2023年跨年的时候来北京跨年的,2024就真的到了北京工作,这一年算是集中发生了很多事情,比23年22年都精彩一些。


有一些错误的决定,也有一些正确的决定。总得来说差强人意,但是依旧悲观。


裸辞


上家公司是在上海,从本科毕业后就在这家公司工作,工作了两年吧,在这家公司认识了很多玩的很好很好的朋友,现在也时不时的会聚一下,群里总是会有各种话题
大家一起抱怨生活,一起玩乐,能在工作后认识这么要好的朋友实属幸运。


我们在上海的时候经常去唱歌,钓鱼,公园,晚上睡不着了在群里吆喝一声 喝点? 下一分钟就到了酒桌上,大家很合得来,都是性情中人,有时候会喝的多一点,然后第二天都请假了哈哈哈。


大家经常约出去玩,我们去过宁波、苏州、乌镇、无锡、扬州等上海周边的城市玩了个遍,现在想想那时候确实挺开心的,大家单身的居多,都是没有什么羁绊,玩得很高兴,压力大了偶尔打打麻将,去酒吧喝喝酒,然后接着周一上班,妥妥打工人生活实录,就靠周末过日子呐


但是公司效益不好,开始陆续裁员,除了我之外都回去了老家所在地工作,之后在上海就不好玩了,没有朋友,也没有钱,在这家公司两年了没有涨过工资,工作也是没有什么乐趣,那时候离职的心到达了顶峰,得知公司今年也不会涨薪后,我选择了裸辞不要裸辞!辞职后压力很大


离开


提了离职后,和项目上的同事们一起吃了一个散伙饭,然后在上海最后3个玩的比较好的朋友吃了顿饭,差不多我就留了一周时间在上海再待一周,看看上海,以后估计来的就比较少了。


那一周是真的舒服,没有工作压力,那时候也不想找工作,一周就是放松,不想任何事情,辞职的事情没有告诉父母,所以没有任何羁绊,天天吃了玩,玩了睡,差不多持续了一周后


我收拾行李开始北漂了,收拾行李的时候回想到刚毕业到上海漂泊,孤身一人,谁也不认识,搬家3次,发烧生病不及其次,其实就是加班太多了,压力太大导致的


当时和我非常要好的哥们苏总,我俩都阳了好几次,发烧好几次,什么病流行,我俩就得什么病,你看我们多时髦,在上海的两年还是收获了很多很多,但是已经不适合现阶段的我了,那就走!下一站北京!


进京


还好有一个非常要好的好哥们在北京实习,租的房子有一个月的空窗期,没有人住,所以我就可以白嫖一个月的住宿了,这一个月的白嫖住宿对我来讲还是很重要的,给我提供了一个月的找工作面试学习的时间。


非常感谢我这位朋友的照顾,才使得我在偌大的北京有一个可以休息的地方。感谢飞哥


从上海坐高铁到北京,自己拖着行李,正好那天晚上还在下雨,我见到了飞哥,飞哥请我吃了一顿饭后,我到了他的出租屋,那天晚上迟迟睡不着觉,想了很多事情,也担心找不到工作之后怎么办,回老家?回老家干什么工作呐?这或许是当代年轻人的痛吧


第二天睡醒后,我就开始找工作之旅了,没有接着休息了


现在的工作是真的不好找,主要还是自己核心竞争力不够导致的,经济形势不容乐观。到北京后也没有怎么玩,直接开始复习找工作,疯狂面试投简历,那段时间还是很规律的每天都在面试学习。


image.png


经过小一个月的备战,拿到了几个offer,最终选择了现在的这家公司


入职


拿到offer后很快就入职了,准备入职体检,体检tmd尿酸高点,我一般体检指标都是正常的,这次是第一次有指标不正常,不禁感慨,工作两年后确实伤身体


约好入职时间后,就休息了一两天,然后入职了现在这家公司,挺喜欢现在这家公司的,氛围很好,是一个创业公司,也不加班


在这家公司学习了很多,未来打算学习一下外语 这家公司有美国员工,正好练习一下口语


恋爱


啊哈哈哈,来北京一段时间后,就谈恋爱了,这里就简单说一下,留一点个人隐私


买房


在北京半个月稳定了后,我告诉了父母,我换工作到了北京,父母很开心,老家是邯郸的,距离北京不算远,基本上可以每周末都回家,经过考虑后,决定在邯郸买一个房子


在北京是不太可能了,未来大概率是要离开北京的,或早或晚吧,具体时间随缘吧


我拿了30%的首付钱,爸妈拿了70%的首付钱,我在邯郸买了一个三居室,在大学对面,我很喜欢这个地段,以后没事了大学里面看看腿也挺好的


这里也不细讲了,留点隐私


你呐?


你们呐,过的好吗?过的开心吗?


祝大家2025,天天开心








2024-12-12 于北京出租屋


作者:吃饺子不吃馅
来源:juejin.cn/post/7450878328036982819
收起阅读 »

不容易,35岁的我还在小公司苟且偷生

前言 前几天和前同事闲时聚餐,约了两个月的小聚终于达成了,程序员行业聚少离多,所幸大家的发量还坚挺着。 期间不可避免地聊到了自己的公司、行业状况以及对未来的看法,几杯老酒之后,大家畅所欲言,其中一位老哥侃起了他的职业生涯,既坎坷又无奈,饭后想起来挺有代表性的,...
继续阅读 »

前言


前几天和前同事闲时聚餐,约了两个月的小聚终于达成了,程序员行业聚少离多,所幸大家的发量还坚挺着。

期间不可避免地聊到了自己的公司、行业状况以及对未来的看法,几杯老酒之后,大家畅所欲言,其中一位老哥侃起了他的职业生涯,既坎坷又无奈,饭后想起来挺有代表性的,征得他同意故记录在此。

以下是老哥的历程。



cold.jpg


程序员的前半生


我今年35岁,有房有贷有妻女有老父母。


出生在90年代的农村,从小中规中矩,不惹事不喧哗不突出,三好学生没有我,德智体美没有全面发展。学习也算努力,不算小题做题家,因为只考了个本科。


大学学费全靠助学带款,勤工俭学补贴日用,埋头苦干成绩也只在年级中等偏下水平。有些同学早早就定下了大学的目标,比如考研、比如出国、比如考公,到了大三的时候大家基本都有了自己的目标。而我的目标就是尽早工作,争取早日还完带款,因此早早就开始准备找工作。

也许是上天眷顾,不知道怎么就被华为看重了(那会华为还没现在的如日中天,彼时是BAT的天下),稀里糊涂的接受了offer,没想到却是改变了后面十年的决定。


2013年,深圳的夏天阳光明媚,热气扑鼻,提着一个简单的箱子进入了坂田基地。

刚开始,工作上的一切都很新鲜,每个人都在忙碌,虽然不知道他们在忙什么,但感觉很高级的样子。同期入职的同事都比较厉害,很快就适应了工作,而自己还是没完全应对工作内容,于是下班之后继续留在公司学习,顺便蹭饭。

就这样,很快就一年过去了,自己也慢慢熟悉了工作节奏,但是加班也越来越多了。对于自己来说,为了过节点,6点是晚饭时间,9点是下班时间,12点正式下班。

平凡的日子没什么值得留恋,过一天、一个月、一年、四年都没什么两样,四年里学习到了不少的知识,也数了很多次深圳凌晨的路灯数。


作为深漂,没有遇到深圳爱情故事,也对高昂的房价绝望,于是决定回到二线城市,成为一名蓉漂。
2017年,还是和四年前一样的行李箱,出现在了老家的省会城市,只是那时的我没有了助学打款,怀里也攒下了一些血汗钱。

那时互联网行业发展还是如火如荼,前端的需求量也很大,也得益于华为公司发展越来越好,自己的华为经历很快就拿到了几个offer,选了一家初创公司,幻想着能有一番成就。


2018年底,眼看着房价越长越高,某链中介不断地灌输再不买明天就是另一个价了,错过这个村就没这个店了,也许是想有个家,也许是想着父母能到省会里一起住,拿出自己做牛马几年的积蓄加上父母一辈子辛苦攒的小十万的养老钱购买了城区里的新房,那会儿的价格已经比前两年涨了一倍多,妥妥的高位站岗,不过想着自己是刚需也不会卖,因此咬咬牙掏出了全部的积蓄怒而背上了三十年的房贷。


房子的事暂时落定了,全身心的投入到工作中,没想到老板只想骗投资人的钱,产品没弄好投资人不愿跟进了,坚持了三年,期间各种断臂求生,最终还是落了个司破人走的境地。


2020年,30岁的我第一次被动失业了,幸运的是也找到了另一半。为了尽可能节省支出,房子装修的事我们都是亲力亲为,最后花了十多万终于将房子装好了,虽然很简单但毕竟是自己在大城市里的第一套房子,那一刻,感觉十年的付出都是值得的。

背着沉重的房贷,期望能找到一份薪资稍微过得去的工作,于是在简历上优势那行写了:“可加班”。依稀记得有些HR对我进行了灵魂拷问:结婚了吗?有小孩了吗?你都30岁了还能加班吗?。我斩钉截铁地说:只要公司有需要,我定会全力以赴!


2022年,我们的孩子出世了,队友辞去了工作全心全意带小孩,而我更加努力了,毕竟有了四脚吞金兽,不得不肝。

虽然工作很努力,但成果一般,不是公司的技术担当,也不会是技术洼地。


2023年的某一天,和之前的364天一样的平淡,在座位上解Bug的我突然感觉到一阵心悸,呼吸不畅,实在不行了呼唤同事叫了120,去医院一套检查下来没发现什么大问题。医生询问是不是工作压力太大,平时加班很多?我说还好,平时也就加班到9点。医生笑了笑说你这种年轻人我见多了,都是压力大的毛病,平时工作不要久坐盯着屏幕多站起来走走。他让我回家多休息,回去后观察了几天还是偶尔会有心悸,再去了另一个医院进行检查,也是没有明确的诊断结果,只是说可能是这个问题,又可能是另一个问题。

过了1个月后,身体上的问题不见好转,我辞去了工作。


2023年末,找了一家小公司,也就是我现在的公司,工资没有涨,仔细算起来还变相下降了。

还是做的业务需求,也没有领导什么人,管好自己就行,直属上级还是个工作几年的小伙。这家公司主要的特点是不加班,技术难度不高,能做多少就是多少,前提是要报风险,领导也不会强迫加班。


就这样到了2024,神奇的是我已经很久没有心悸的感觉了,不知道是不加班还是心态转变的原因。
家里的小朋友也长大了,会说话了。我现在每天下班最温馨的的是她开着门期待我回家的那一刻,她的期盼的眼神就是我回家的动力。


公司在2024年也裁了不少人,领导也找我谈过问问我的想法,我说:我还是能胜任这份工作的。领导说:公司觉得你年级大了一些,工资虽然不是最高,但不太符合行情,你懂的。我说:我懂,可以接受适当的降薪。
就这样,我挺过了2024,然而过了一周领导走了。


2025年,我35周岁了。
现在的我已经彻底接受自己的平庸的事实了。在学生时代,从来都不出色,也不会垫底,就是那类最容易被忽略的人。在工作时代,不是技术大牛,也不是完全的水货,就是普普通通的程序员。


如果说上半生吃到了什么红利,只能说入坑了计算机这行业,技术给我带了收入,有了糊口的基础。没进股市,却被房价狠狠割了一道。


35岁的我,没有彻底躺平摆烂,也没有足够奋发进取。

35岁的我,有着24年的房贷,还好61岁的时候我还在工作,应该还能还房贷。

35岁的我,不吃海鲜不喝酒,尿酸500+。

35岁的我,人体工学椅也挽救不了腰椎间盘突出。

35岁的我,头发依然浓密,只是白发越来越多。

35岁的我,已经不打游戏,只是会看这各种小说聊以慰藉。

35岁的我,两点一线,每天挤着地铁,看众生百态。

35岁的我,早睡早起,放空自己。

35岁的我,暂时还没有领取毕业大礼包,希望今年还能苟过。

35岁的我,希望经济能够好起来,让如我一般平凡的人能够有活下去的勇气。


诸君,下一年再会~祝你平安喜乐,万事顺遂!


作者:小鱼人爱编程
来源:juejin.cn/post/7457567782470385705
收起阅读 »

最新 GitHub 骗局!千万别中招!

今天一早,焚香沐浴更衣,打开全球最大同性交友网站,准备好好摸鱼;突然方向通知多了一条: 正疑惑是触发是 GitHub 的什么隐藏关卡呢,点进去一看: 一个 21 年的创建 issue?但是有个新的评论: 这个评论的大意是: 喂!x毛! GitHub 瞎...
继续阅读 »

今天一早,焚香沐浴更衣,打开全球最大同性交友网站,准备好好摸鱼;突然方向通知多了一条:


image.png


正疑惑是触发是 GitHub 的什么隐藏关卡呢,点进去一看:


image.png


一个 21 年的创建 issue?但是有个新的评论:


image.png


这个评论的大意是:



喂!x毛!
GitHub 瞎了眼相中你了,有个很适合你的职位,年薪高达 18w 刀乐!
赶紧来申请啊,各种福利各种巴适!
但是有记得在 24 小时内点击这个链接来申请哦!过时不候!
后面芭啦芭啦@了一大堆人,其中我的用户名赫然在列!



他真的!我哭死!原来天上真的会掉馅阱 😢...


但是仔细一看,评论的这个人,是默认头像。不对劲!非常不对劲!遂点进其主页一看:


image.png


啥也没有...


这时候事情就很明显了,然后我就去 GitHub 社区找了一下相关的反馈,果不其然,两天前开始有人在反馈相关问题:


image.png



原讨论传送门:github.com/orgs/commun…



于是笔者在隐私模式下打开@我的那个评论附上的链接:


image.png


这个页面会请求你使用 GitHub 授权登录,并且要求你授权各种高级权限;而一旦你授权了,大概率会发生的第一件事,就是你的帐号会在各种 issue 中发布上面那条“GitHub 求职骗局”的评论,以导致更多的人受骗...



截至笔者写下这篇水文时,该钓鱼网站链接已经无法打开。



而在早上笔者在 github.com/orgs/commun… 中留下评论后,陆陆续续又有上百个全球各地的开发者进行了反馈。甚至有领先一步的好哥们已经直接出手向域名注册商、域名托管服务商进行了举报,并收到了反馈:


image.png


而这,仅仅是在笔者写下这篇水文前的 23 分钟(一切发生得太快...


不仅如此,在笔者截完本文第三张图后,提及我的那条评论已经删除了 🤪 (一切发生得实在太快...


不不仅如此,在笔者敲完上一句话后打算再次确认一下发出评论那个用户(第四张截图),发现他已经被封禁了...


image.png


好家伙,这发生得也太快了吧!赶上直播了???


估计这一波,有不少帐号也受到波及,最好确认一下自己的帐号是否有被影响(吓得笔者又刷新了一下页面确认自己有没有被封禁)。


这也让笔者想起最近 GitHub、NPM 等各种平台都在极力地推动用户启用双因素身份验证(2FA),以提高用户帐号的安全;这样看来,确实是一个明智之举。


最后还是提醒一下各位:


不清楚来源的链接不要点!不清楚来源的链接不要点!不清楚来源的链接不要点!


就这样。


作者:Nauxscript
来源:juejin.cn/post/7337666469903122472
收起阅读 »

用AI做了个「微信红包封面」,还能卖钱?

点赞 + 关注 + 收藏 = 学会了 🧨快过年了,该发红包了🧧 使用默认红包封面彰显不了个性,去「微信红包封面开放平台」定制一个吧。 👉 cover.weixin.qq.com 👈 我是用自己公众号注册的。没有公众号的话也可以用自己的视频号去注册一个。 登录...
继续阅读 »

点赞 + 关注 + 收藏 = 学会了


🧨快过年了,该发红包了🧧


使用默认红包封面彰显不了个性,去「微信红包封面开放平台」定制一个吧。


👉 cover.weixin.qq.com 👈


01.png


我是用自己公众号注册的。没有公众号的话也可以用自己的视频号去注册一个。


登录后,点击页面右侧的“定制封面”就会跳转到创建红包封面的界面。


02.png


接下来就是填资料,上传你做好的封面图即可。


需要注意的是,「封面简称」建议填你的公众号或者视频号的名字,这样可以降低审核要求。如果你填其他内容就需要提交相关的材料「证明材料」给微信审核。


03.png


但!但!但!


现在没有免费的「微信红包封面」了,1元1个。


04.png


不懂设计又想弄个好看的红包封面怎么办?


交给AI吧😝


我已经写过好多篇「AI绘画」相关的教程,有条件(电脑配置足够高)的工友可以在自己电脑安装好 Stable Diffusion,在本地创作。


比如我这个封面(英雄联盟的金克丝)就是在自己电脑用 SD 做出来的。


05.png


电脑配置一般的工友可以用线上平台,比如哩布哩布(liblib.art/)。我这个封面就是用哩…


06.png


用哩布哩布的好处就是案例特别多,自己不懂怎么写提示词,可以先逛逛哩布哩布,看到喜欢的就选择“做同款”。也可以在“做同款”的基础上适当的修改一下提示词,按你的想法去创作。


07.png


在写本文时,哩布哩布每天会刷新300点算力值给你创作。简单来说,可以白嫖!


除了哩布哩布外,我之前还分享过数款AI绘画的平台,有需要的工友可以去看看 👉 mp.weixin.qq.com/s/nMZMfErDv…


「红包封面」微信收1元1个,那是不是可以帮别人定制封面赚点小钱呢🤔


08.PNG




金克丝的含义就是金克丝


IMG_6296.PNG


作者:德育处主任
来源:juejin.cn/post/7455880105451323404
收起阅读 »

以我两年多前端的血泪😭经验,给大家一点警示

工作两年多了,踩过了许多坑,希望大家不要踩,常常想如果我刚毕业就知道这些东西就好了,但是没有如果 一个人现在做了他多年以后认为正确的事情,他是很幸运的 永远不要期待领导主动加薪 不会还有人期待着领导某一天主动找你,小张,你来一下办公室,我有点事情给你说 到...
继续阅读 »

工作两年多了,踩过了许多坑,希望大家不要踩,常常想如果我刚毕业就知道这些东西就好了,但是没有如果



一个人现在做了他多年以后认为正确的事情,他是很幸运的



永远不要期待领导主动加薪


不会还有人期待着领导某一天主动找你,小张,你来一下办公室,我有点事情给你说

到办公室后,领导:你最近表现不错,公司决定给你涨薪20%,下个月开始执行

你一脸春梦样子


大哥醒醒吧,梦里才有!


现在大部分公司不会主动给员工加薪,能不降薪就算不错了,没有领导无缘无故能给员工加薪,绝大部分都是这样的,老板和员工本身就是利益冲突的,你挣的钱多了,老板怎么买法拉利呐


所以永远不要期待领导给你主动加薪资,你需要有筹码,有底气,当然筹码与底气很重要,但是更重要的是:你要主动争取


主动权要始终掌握在自己手中


永远不要裸辞


少看网上的一句梦想仗剑走天涯,就裸辞冲到了318


裸辞只会导致你找工作的时候更加被动,和hr聊薪资的时候更加被动,徒增你的焦虑


从某种角度来说,裸辞百害无一利,除非你在这家公司非常非常非常不爽了,再裸辞,当然你有足够多的钱另当别论,但是你大概率没有,都tm干程序员了,你能有多有钱?


不要裸辞,动了辞职的念头,那就着手准备,公司的活干的说得过去就行


慢慢找,一定要找到比现在待遇好的再辞职,不要降低标准,除非一直拿不到理想的薪资,不然不要将就,怕就怕这一将就,后面都得将就了。


一开始干程序员你就得明白,你得走


这个走有两层意思

1、你得跳槽,刚开始的时候千万不能觉得安逸,不想走,不想跳槽, 懂得都懂,这行得跳槽涨薪
你可能说安逸,不累,不想走,行,你20多k,不累,不走,很好,你很聪明


怕就怕有哥们11-12k的贪图安逸不走,你说你这薪资安逸个吊毛啊,再安逸就废了


该走就走


2、你能干到40?
大部分都够呛吧,如果40还是一线大头兵程序员,嗯,,,,,,很难,

刚开始干程序员就得明白,得在短期内快速攒钱,年纪大了得谋求后路,别以为现在挣的还可以,就嘎嘎花钱,到你年纪大一点有的后悔,得攒钱留后路


要敢于要价格


这个世界从来都撑死胆大的,饿死胆小的

从某种角度来说,你值多少钱取决于你自己敢要多少钱,你说老板会觉得要10k的程序员有多大价值吗?


大胆点,敢于争取自己想要的价格才是正道


自信点,大家都那个b样


世界是一个巨大的草台班子,你以为别人牛逼的很,其实他也以为你牛逼的很,都一样,自信点,都挺傻逼的


现在这家公司的老板说过一句话,使我受益无穷



人一定要有自信,大家都那样,你以为他牛逼,其实也就那样,时刻问问自己,凭啥他行,我不行



问问自己有核心竞争力吗


大部分人都没有,程序员的竞争力无非这几种

1、名校学历

2、github 500star+项目作者

3、长期积累的博客

4、社区有知名度、影响力(掘金等)

5、项目有亮点、难度

6、大厂实习工作经历

7、竞赛奖牌

没事多更新简历,多投一下,知道自己在市场上还能混的下去不


踏踏实实卷一段时间


很多人都在说不要卷。开玩笑,市场资源有限,不卷怎么行

但是不要焦虑,踏踏实实的,认认真真的卷一段时间,自己有了提升后,在谋求发展。

自身没有价值之前,说再多都是瞎掰扯,没屌用


俗称,耐得住寂寞,踏踏实实的做学问,这一点我得深刻反思



以上纯属瞎扯,如有不赞同,那就是你对



作者:吃饺子不吃馅
来源:juejin.cn/post/7457417025930117154
收起阅读 »

App出现技术问题,这样的中国电信让用户糟心了

web
前言 最近在中国电信app上销户一张中国电信山西区的电话卡,一打开销户界面我就惊了 点开一看,写入的本地变量、cookie一览无遗。 查看数据 存在采集用户手机型号、来源等数据行为产生的cookie 最引人注目的就是 zhizhendata2015jss...
继续阅读 »

前言


image.png


最近在中国电信app上销户一张中国电信山西区的电话卡,一打开销户界面我就惊了


image-20250105103537705


点开一看,写入的本地变量、cookie一览无遗。


image.png


查看数据


存在采集用户手机型号、来源等数据行为产生的cookie


最引人注目的就是


zhizhendata2015jssdkcross={
"distinct_id": "MTkxOTZhYzk3YTAyMDItMDgxMjMwYmRlOTFhOWU4LTQ3NzE2ZTBmLTM2NzkyOC0xOTE5NmFjOTdhMWE5NQ==",
"
first_id": "",
"
props": {
  "
$latest_traffic_source_type": "直接流量",
  "
$latest_search_keyword": "未取到值_直接打开",
  "
$latest_referrer": "",
  "
_latest_utm_scha": "utm_ch-010001002009.utm_sch-hg_sy_pdkp-2-125971000001-10519100001.utm_af-1000000037.utm_as-0043300037.utm_sd1-default",
  "
_latest_utm_sd1": "app-充流量-本地推荐",
  "
_latest_utm_sd2": "",
  "
_latest_shopid": "189.WAP.llrb-2079",
  "
_latest_utm_ch": "hg_app",
  "
_latest_utm_sch": "hg_sy_pdkp_kw02",
  "
_latest_utm_as": "hg_19y15GBwxllb"
},
"
login_type": "",
"
utms": {
  "
shopid": "189.WAP.llrb-2079"
},
"
$device_id": "19196ac97a0202-081230bde91a9e8-47716e0f-367928-19196ac97a1a95"
}


简单解释一下各种参数


image.png
很显然 ,这是一个用户行为追踪工具,记录你从那个平台点进来(广告投放)、你手机是啥样的(用户画像)、你搜索了什么。可能还会有你住哪里之类的数据



  • 博主一下懵了,之前常听人说大数据时代没有什么秘密,还不以为然。今日一遇还真是阿


登录状态与服务取消cookie


SXH5_CANCEL_SERVICE_LOGINSTATUS=SXH5_CANCEL_SERVICE_a2d95a5a764d4744b1eb1e468b583287

SXH5_CANCEL_SERVICE_LOGINTYPE=fmknjikneolbnhclejikfnbggkmnookc



  • 这两没什么好说的,看不出来啥


查看持久化数据


image-20250105111122637


userInfo={"type":"object","data":{"userName":"","userId":"","userAddress":"","facePhoto":"","frontImage":"","phone":""}}

vConsole_switch_y=335

loginType=sjhocr

xhAccount={"type":"object","data":{"xhzkAccount":"15383404397","xhfkPhone":"","xhkdAccount":""}}

authorPlate=xh

vConsole_switch_x=92

orderId=SXSMRZH5XH202501042248308427503

__DC_STAT_UUID=17360018747207051970


  • 这段数据也没啥好看的,有一些手机号、订单编号、和证明是微信小程序的__DC_STAT_UUID 项


image-20250105111458145



  • 更多就不继续探索了,这里的填写号码获取验证码控制台正常输出。。。。


问题可能产生原因



  • 首先,得知道中国电信app现在的模式是怎样的。

  • 据博主个人观察,电信app页面虽然都一样,但每个地区各自为营。如果你使用福州的电信手机卡登录,那么是跳转到福州电信负责的页面,如下图


s



  • 所以本次app出现问题,是山西电信没有处理好app端


image.png



  • 山西电信微信小程序是没什么问题的,而他的app没有做好对接,要么版本不一样……


吐槽



  • 我有个朋友之前注销电信流量卡时,被告知要去号码归属地才能销户。。这归属地离他十万八千里,过去就为了销卡显然不划算。于是他去工信部12300(微信公众号 现改名为 电信用户投诉 )投诉才成功线上销卡。

  • 电信现在按省来处理业务,如果你电信卡丢了且忘记卡号、归属地,那只能通过线上投诉才能得知自己卡号、归属地,不然各省是无权查别省号码。

  • 我线上销户时,客服A要求先交40元月租才能销户,但这张卡我从未使用,为何会产生月租?联系客服B后,他让我提供身-份-证照片、委托书及手持委托书照片,最终未交钱完成注销。但不同客服的说法不一,且身份信息完全暴露给客服,让人不安。


作者:Qiuner
来源:juejin.cn/post/7456898384352362522
收起阅读 »

这五年,我学这么多东西再没有高学历背景下,有没有意义

今年的10月初我被辞退了,公司为盈利,部门整体裁掉,感慨挺多的。也是我工作以来待的最久的一家单位了,从原来的菜鸟到现在能算是合格的前端工程师,不管怎么说,我很感谢这个平台。被辞退以现在的环境制定要面临降薪,或者换个没有福利待遇那么好的单位。这五年我得到的太多了...
继续阅读 »

今年的10月初我被辞退了,公司为盈利,部门整体裁掉,感慨挺多的。也是我工作以来待的最久的一家单位了,从原来的菜鸟到现在能算是合格的前端工程师,不管怎么说,我很感谢这个平台。

被辞退以现在的环境制定要面临降薪,或者换个没有福利待遇那么好的单位。

这五年我得到的太多了,可能有人说如果你在别的单位应该也会得到你应得的,这个说法确实没毛病。我只不过是一个打工仔,平台不过是带我见识了一些上限,如果我不愿意去学,可能也收获不了这么多。那么就从生活、技术等等方面展开来说下我得到了什么。

生活

刚入职这家公司没多久(2019年),我就跟我老婆处对象了。是的我们在2023年10月4号结婚了,也很顺利我们在12月份接着接到喜讯我们有宝宝了。宝宝出生在2024年10月3日(女宝),很漂亮,大眼萌娃。照片我放下面给各位叔叔姨姨们看看:

4601734486091_.pic_hd.jpg

4611734486094_.pic_hd.jpg

4631734486100_.pic_hd.jpg

买房:没逃得了当房奴(被逼的),在2023年8月份我们在南京市浦口桥北买了个小三室,总价150W。首付了70W,带款80W,20年,每个月要还5700左右。不好的是今年房子了好多钱。我们小区同户型的已经有挂120+的了,成交价更低

之前有个同事大哥说过,如果你买了房子,能娶妻生子,那么房子的价值就够了,它跌就跌吧。落了个媳妇+孩子了。

这里给还没有买房的朋友一些建议:带款要贷30年(前期压力小,后面可以提前还款), 买毛坯的话一定要预留好装修资金,其实我不建议买毛坯,那个时候你就会要负担房贷+房租+装修(我就是个例子:后悔si了😭),还要晾着一年半载的才能入住,最好能买个二手房直接能入住的。

我这几年在这家公司待遇也涨幅了几次:

第一次是2020年10月份,觉得自己还凑合,想去外面看看,当时确实环境大好,也拿到了不错的涨幅。后来就是我当时部门的前端领导全力留我,觉得我很负责,提出给我涨幅3.5k

第二次是2022年3月份,也是我这个前端领导要换平台,不在这个部门带领我们了。我也想出去看看😁,结果是部门领导留我了涨幅4k

第三次是2023年12月份,我把我们的一个用户后台管理(老旧难用)在一次迭代中,用时7天把14个模块整体重构(公司框架+公司UI组件),就是一天写两个模块,然后交给测试同学同步测试,第二天把bug和两个新模块同步修改好继续提测。7天后上线,新的web页很好用(都是老的web衬托的),得到了部门领导的主动涨薪1.5k

可以说我运气好,也可以说我遇到了好领导,我可能是有点价值的,但是我确实是幸运的。

技术

  1. (2019)、校招生好厉害

高校的校招生竟然这么厉害,这是我在这家单位接触校招生或者说应届生的真实感受。 也是他们本身基础就很扎实,有编程思想,有领导带领规划成长路线,又很积极爱学确实成长很快。

我开始了重新学了下ES6,买了一本阮一峰老师的《ES6标准入门》,来回看了3遍,深入理解了解构,数组的some、every字符串的:startsWith、endsWith、padStart、padEndSet、MapPromise等等。我觉得它帮助我特别大,如果没有这本书我或许会看到一些同事写的语法,我不认识的语法。为我的js奠定了一定的基础。

  1. (2020)、同事竟然手写正则
  • 再一次跟同事协作中需要检验一个ip段,他竟然给我直接手写手写,大佬真真厉害。然后我就去重新学习了正则表达式基本能达到写一些简单的表示式。
  1. (2020)、前端领导让我看看eggjs,了解怎么的用法,后面需要跟我做一个东西
  • 在这个里面学到了很多关于node的相关知识。
  1. (2020)、前端大屏大佬,我们有一个专门写大屏的前端大佬
  • 跟着他学到了怎么做适配rem、em、vw、postCss,使用echarts,并认识了d3js(后面刚好会用到,会更深入了解)
  1. (2020)、前端领导让我学习nginx,起个服务3000端口的时候能访问到百度的页面
  • 这里用到了转发服务以及代理资源,让我在后面对前端资源处理以及处理代理问题时有了很大的帮助,我搭建博客等好多地方都用到了。
  1. (2020)、前端领导让我用谷歌插件开发一个chrome插件,主要是 读取数据(标签页中的某个窗口)到周报生成渲染。

其实到这里我都没有学习编码规范,对组件设计的思想也了解不多,基本上就是野蛮开荒。本来一直计划给我做代码codereview,看看怎么能帮我做些规范的提升,一直没太多机会。后来就是他自身发展走了去了别的单位,然后换了个空降领导,他开始组织我们创建各种规范拦截,eslintgit提交拦截。

  1. (2021)、定义相关规范拦截 eslint、git
  • eslint: 用的airbnb的规范。还是蛮严格的帮助我纠正了不少代码缺点。
  • gitcommit 规范,分支规范等等。
  1. (2021)、阅读库源码提升自己的代码规范。我觉得对我帮助最大的是element-ui的源码

2021 年我觉得我最大的进步就是代码质量有了大幅度提升,懂的怎么设计组件了,怎么能写让代码更壮健,懂的了规范带来的价值。

  1. (2022)、我们开始放弃了jenkins做打包构建,换成了gitLab CI CD, 我深入了解并学习了下。
  2. (2022)、前【前端领导】让我协助他开发个微信小程序,有了解到了小程序的相关知识。
  3. (2022)、我们开始做一个图谱产品,拓扑图可视化分析,使用了d3js以及canvas
  • 为了支持大数据的统计以及绘制,在这两年中一直在做数据结构的优化以及接触web Worker、Wasm等,只在可视区域渲染等等优化策略。 算是学到了性能的优化手段,也了解到了图形算法的魅力。
  1. (2022)、学习TS,写了写react Hooks。也了解到了跟vue之前的区别
  2. (2022)、我开始研究怎么生成脚手架,发布NPM包。
  3. (2023)、这年我开始对我们公司平台组的产物做源码学习,学到了babel ASTwebpack插件编写等等,还写了个vscode的插件主要是处理AST的达到函数插桩。
  4. (2023)、这年我开始对之前用到的知识做了总结发表一系列文章(得到了掘金Lv5优秀创作者)。
  5. (2023)、我持续查阅那些好的插件包的源码具体怎么实现的,对编码思想又了更深层次的理解。懂得了怎么做能更好的建立一个可持续发展的方向,技术选型,风险评估等等。
  6. (2024)、这年精力主要是在工作上(大环境太不好了,不想被裁,也算是坚持到了最后),开发大屏,重构了好多老的代码,对产品的用户体验做到了细致的优化。

我学这么多东西有在没有高学历背景下,有没有意义?

实话说我在这次找工作中,对自己的一直努力的方向做了怀疑,还不如好好享受,学习这么多干啥呢? 约面试会被卡在学历上,我很烦恼,有些怀疑自己。我之前在环境大好的背景下,我始终认为多学习,一定能涨工资。

我也会向我老婆吐槽说学这么多又有啥用呢,第一步就被卡死了。是不是统招本科!!!抱歉我不是

她说你比你同学朋友们可能要好多了,他们一年、两年可能就会换个工作,在者说口罩那几年你一直也算很稳定,别人都换了好几家单位了,你知道为啥一直再给你加薪吗?其实都是你努力得来的! 工作嘛,咱们换个就行了,现在大环境不好,不好找是常态,她说没关系的,她还有存款(彩礼钱+自己之前攒下的),你就是一两年不上班都没问题。

是啊!我一直在稳步加薪,待遇在朋友中也还算不错的

没上班怎么可能不焦虑,我是刚好我家孩子出生那个月被裁的,我还等到了小孩20天后才开始找工作,那个时候父母还都在这边,我对双方父母说我是在休产假+年假,在出去面试那几天也是说出去给我闺女办理正件

后来因为孩子要喝奶粉 + 房贷 + 房租 + 装修,其实我很大的压力,老婆虽然没催我给我压力,但是每天还是很焦虑的,有的时候会算我家娃一个月花费多少... 唉!!

一切都是有意义

我有掘金社区优秀创作者,加我的个人博客网站,再加上我会的技术,在加上我还有发表的各类插件,写在简历上都是我的优势,我会刻意去找技术面试官去投简历,我会抓住每次面试机会,努力的去展示自己。

好消息我用时14天收到offer了,一家小单位,双休,待遇降了20%。我知道现在的行情,就是我在多花一个月精力去面试,去找,我可能会更奔溃(最近压力很大),最后的待遇应该也会跟现在这个的大差不差的。 现在都是一个萝卜一个坑,我果断选择入职。

回头看其实我由于我的那些优势,我算约到了不少面试,我总共面试6家,二面了2家,我跟我同时被裁的前端同事聊,他说用时两个月才约到2家面试。我运气真的好的太多了

还有个好消息就是前【领导】11月初找我做一个项目,持续7个月,让我兼职每天干2-4个小时,每个月给我1W。由于我现在通勤+加班,可能没太多精力去做,然后就介绍给我的同事阿祖全职,给了他1.8W

5111735353355_.pic.jpg

5081735352115_.pic.jpg

其实前领导能找到我也是认可我的工作能力,我其实也后悔推荐给朋友了,我应该找他一起兼职这份工作,我俩平分这个1w,毕竟我刚降薪加实习期80%,落差不少。

11月中的时候又有前单位的UI设计师(他很认可我,每次都说我写页面还原度是最高的)找上我说要不要考虑私活报价1.2W,做一个网站+h5,其实1.2w我俩平分不算特别高,但是最后没能接下来。

image.png

12月下我前前【领导】来找我说他们单位可能要裁员,然后呢他搞了这么多年不想在打工了,想着做做产品。他好像看中小程序的市场,他也有些人脉。我其实在第一份兼职1w的没接的时候我也考虑做什么产品化的东西能卖钱。小程序的市场看到某宝好多个卖模版的,还老便宜了,加上我也没有什么人脉就放弃了。这次跟着它们用业余时间搞搞试试。用雷布斯的一句话:我们悄悄搞,没搞成,就当我们没有搞过!!。雄起!!!!

5101735352790_.pic.jpg

接下来的计划

  • 产品化的东西让他们计划,只是定了个初步目标,还暂未执行!
  • 攒钱买个小车(10w),有孩子了没车的话出行不是很方便
  • 我老婆在做xiao红书,做母婴方面的,最近粉丝也达到了600个🔥,继续加油
  • 我在斗音上拍我闺女视频,但是没太多流量,刚刚投了150块钱,得到了40多个粉丝,😭,继续加油吧!!!
  • 我在学习Java,主要是要是做点什么写后端能方便点
  • 搞钱!!!!!!!!


作者:三原
来源:juejin.cn/post/7453120781771341859
收起阅读 »

和后端大战三百回合后,卑微前端还是选择了自己写excel导出

web
前言 对于一个sass项目,或者一个中后台项目来说,导出excel表格应该是家常便饭,本来最简单的实现方式是后端去做表格,前端请求接口拿到一个地址下载就行了。但是,因为我们这个项目之前就是前端做表格,加上这个表格相对比较复杂需要合并行和列,后端不会加上又有别的...
继续阅读 »

前言


对于一个sass项目,或者一个中后台项目来说,导出excel表格应该是家常便饭,本来最简单的实现方式是后端去做表格,前端请求接口拿到一个地址下载就行了。但是,因为我们这个项目之前就是前端做表格,加上这个表格相对比较复杂需要合并行和列,后端不会加上又有别的项目堆积没有时间研究,所以就是后端提供数据,前端来做表格。


那里复杂


image-20241209095449488.png


可以看到,有二级标题,还有行的合并,如果仅仅是二级标题,倒是可以直接写死,但是行的合并是根据数据去计算该合并那些行的,再比如后面如果有三级标题,四级标题的需求呢?那不是又寄了,所以我选择将这个封装成一个方法,当然也是在网上找大佬们的解决方案实现的,东抄抄西抄抄就实现了我想要的功能。


传参


既然封装成一个方法,最好就是传入数据,表头,文件名后,就能自动下载一个excel表格,这才是封装的意义。代码并不是人,只能根据你设定好的路去走,所以数据的结构就显得很重要了,这个函数想要接收什么样的数据结构,要怎么去处理这些数据结构。


表头 header


表头接收一个数组,每一项有title,prop,children(如果有子级标题),title即为列名,prop为数据属性绑定名,children为子标题。


const header = [
{
'title': '券商(轉出方)',
'prop': 'orgName',
       'width': '100px'
  },
  {
       'title': '存入股票',
        'children': [
                {
                   'title': '存入股票名稱/代碼',
                   'prop': 'stockNameCode',
      'width': '100'
                },
                {
                   'title': '股票數量(股)',
                   'prop': 'stockNum',
                    'width': '100'
                },
                {
                   'title': '成本價(HKD)',
                   'prop': 'stockPrice',
                   'width': '100'
                }
          ]

  }
]

数据 dataSource


数据也是接收一个数组,但是这里需要做一个处理,因为每一项的children是一个数组,可能会有多个值,换句话来说,下面只有两条数据,分别是id为1和id为2,但实际上在excel表格中需要显示3行,所以需要处理一下。


const dataSource = [
  {
      id:1
      orgName:‘a’,
      children:[
      {
               stockNameCode:'A1',
               stockNum:'A2',
               stockPrice:'A3'
  },
          {
               stockNameCode:'B1',
               stockNum:'B2',
               stockPrice:'B3'
  },
]
  },
  {
      id:2
      orgName:'b',
      children:[
      {
               stockNameCode:'A1',
               stockNum:'A2',
               stockPrice:'A3'
  }
]  
  },
]

处理后的数据(也就是将children解构了,变成3条)


[
  {
      id:1
      orgName:‘a’,
      stockNameCode:'A1',
      stockNum:'A2',
      stockPrice:'A3'
  },
  {
      stockNameCode:'B1',
      stockNum:'B2',
      stockPrice:'B3'

  },
  {
      id:2
      orgName:‘b’,
  stockNameCode:'A1',
      stockNum:'A2',
      stockPrice:'A3'  
  }
]

sheetjs前置知识


对于我们前端生成excel,基本都是使用基于sheetjs封装的第三包,最经常使用的是xlsx,我这里因为对表格做了一些样式所以使用的xlsx-js-style,xlsx-js-style是提供了很多样式的,比如字体,居中,填充,具体大家可以去看官网。因为可能有些人是没做过excel的需求的,所以这里简单说一下生成excel的一种主流程。


import XLSX from 'xlsx-js-style'
// 需要一个二维数组
var aoa = [
  ["S", "h", "e", "e", "t", "J", "S"],
  [  1,   2,   ,   ,   5,   6,   7],
  [  2,   3,   ,   ,   6,   7,   8],
  [  3,   4,   ,   ,   7,   8,   9],
  [  4,   5,   6,   7,   8,   9,   0]
];
// 将二维数组转成工作表
var ws = XLSX.utils.aoa_to_sheet(aoa);
// 创建一个工作簿
var wb = XLSX.utils.book_new();
// 将工作表添加到工作簿
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
// 生成excel
XLSX.writeFile(wb, "SheetJSExportAOA.xlsx");

导出的表格,这是官网的demo: xlsx.nodejs.cn/docs/api/ut…


image-20241210090608300.png


所以封装这个函数,主要流程也是和这个一样的,只不过我们要做的时候,将传入的参数处理成我们想要的二维数组,以及在这基础做一些合并,样式的操作,下面介绍了一些属性的作用,具体大家还是需要去官网查看的。


ws['!merges']


ws['!merges'] 是工作表对象 ws 的一个属性,用于存储工作表中的合并单元格信息,该属性的值是一个数组,其中每个元素都是一个对象,描述了一个合并单元格区域


// s是start e是end合并单元格区域的起始位置和结束位置,
// r是行 c是列
ws['!merges'] = [
{ s: { r: startRow, c: startCol }, e: { r: endRow, c: endCol } }
];

比如{ s: { r: 0, c: 0 }, e: { r: 0, c: 1 } } 表示合并从 A1(第 1 行第 1 列)到 B1(第 1 行第 2 列)的单元格。


ws['!ref']


ws['!ref'] 是工作表对象 ws 的一个属性,用于表示该工作表中数据的范围引用。这个范围引用是一个字符串,遵循 Excel 的单元格范围表示法,格式通常为 A1:B10,其中 A1 是范围的左上角单元格,B10 是范围的右下角单元格


ws['!cols']


ws['!cols'] 是工作表对象 ws 的一个属性,它用于存储工作表中列的相关信息,比如列的宽度、隐藏状态等


主函数


有了这些前置知识,相信你肯定是能看懂这个主函数的,我们先从主线上来看,不去研究这个函数做了什么,只需要看他得到了什么,某一个函数的细节我们后面会有介绍。



header 表头


dataSource 数据


fileName 文件名



import XLSX from 'xlsx-js-style'
function exportExcel (header, dataSource, fileName) {
 // 根据表头数组去计算行数和列数
 const {row: ROW, col: COL} = excelRoWCol(header)
 const aoa = []
 const mergeArr = []
 
 // 根据表头初始化aoa 二维数组
 for (let rowNum = 0; rowNum < ROW; rowNum++) {
   aoa[rowNum] = []
   for (let colNum = 0; colNum < COL; colNum++) {
     aoa[rowNum][colNum] = ''
  }
}
   
 // 根据表头以及数据生成,去合并列和行,会处理mergeArr
 mergeArrFn(mergeArr, header, aoa, dataSource, ROW, COL)
   
 // 最后往aoa中 添加表格数据
 aoa.push(...jsonDataToArray(header, dataSource))

 const ws = XLSX.utils.aoa_to_sheet(aoa)
 // 添加样式
 ExcelStyle(ws, header, ROW)
 // 合并
 ws['!merges'] = mergeArr
 // 创建一个工作簿
 const wb = XLSX.utils.book_new()
 // // 将工作表添加到工作簿
 XLSX.utils.book_append_sheet(wb, ws, 'sheet1')
 // 生成excel
 XLSX.writeFile(wb, fileName + '.xlsx')
}
export default exportExcel

相对前面那个下载excel的demo来说,无非就多了根据传入的header和dataSource去初始化生成aoa以及mergeArr,aoa就是前面demo的二维数组,mergeArr表示我们需要合并的单元格,也就是前面提到的ws['!merges'],我们得到这个mergeArr也是为了赋值给它,还有就是给它添加样式了。


excelRoWCol


这个函数是根据表头去确认这个excel的表头有多少行,有多少列,因为我们传入的column,有children,children里可能还有chidren,是一个的结构,所以我们想要知道有多少行和多少列,无非就是去求这颗树的深度和宽度,所以就是两个算法题了。


// 深度递归函数
function treeDeep (root) {
 if (root) {
   if (root.children && root.children.length !== 0) {
     let maxChildrenLen = 0
     for (const child of root.children) {
       maxChildrenLen = Math.max(maxChildrenLen, treeDeep(child))
    }
     return 1 + maxChildrenLen
  } else {
     return 1
  }
} else {
   return 0
}
}
// 宽度递归函数
function treeWidth (root) {
 if (!root) return 0
 if (!root.children || root.children.length === 0) return 1
 let width = 0
 for (const child of root.children) {
   width += treeWidth(child)
}
 return width
}

function excelRoWCol(header) {
 let row = 0
 let col = 0
 for (const item of header) {
   row = Math.max(treeDeep(item), row)
   col += treeWidth(item)
}
 return {
   row,
   col
}
}

mergeArrFn



mergeArr 这个函数就是在修改这个值


header 表头


aoa 二维数组数


dataSource 数据


headerRowLen 表头行数


headerColLen 表头列数



这个函数有两个作用,第一就是将我们初始化的二维数组,用header进行赋值。第二,就是根据表头以及数据去生成mergeArr(赋值给ws['!merges'])。首先,对于header去遍历每一个表头去生成当前这一列的合并信息。假设一个只有二级表头的表头,如果当前这一列有二级标题,便根据子标题去合并主标题那一行所有的列,如果当前这一列没有子标题,便将这一列的第一行和第二行都和合并了。三级表头,四五级表头也是这样的思路。


function mergeArrFn(mergeArr, header, aoa, dataSource, headerRowLen) {
 // 根据header去生成一部分的 mergeArr
 let temCol = 0
 for (const item of header) {
   generateExcelColumn(aoa, 0, temCol, item, mergeArr)
   temCol += treeWidth(item)
}

 // 根据dataSource去生成一部分的 mergeArr
 let rowStartIndex = headerRowLen
 for (const item of dataSource) {
   generateExcelRow(rowStartIndex, item, mergeArr, header)
   rowStartIndex += treeWidth(item)
}
}

generateExcelColumn


这个函数简单来说就是前面所说的,假设一个只有二级表头的表头,如果当前这一列有二级标题,便根据子标题去合并主标题那一行所有的列,如果当前这一列没有子标题,便将这一列的第一行合第二行都和合并了。三级表头,四五级表头也是这样的思路。具体还是得自己理解代码,都有写注释。



aoa 就是那个aoa


row 就是行数


col 就是列数


curHeader 就是当前那一列


mergeArr 就是那个mergeArr



function generateExcelColumn(aoa, row, col, curHeader, mergeArr) {
 // 当前列的宽度
 const curHeaderWidth = treeWidth(curHeader)
 // 赋值
 aoa[row][col] = curHeader.title
 // 如果有子标题也就是说当前这一行就需要合并了
 if (curHeader.children) {
   // 举个例子,假设有一个表头两行两列,需要把他变成第一行只有一列,第二行依然是两列
   // 就需要变成 {s : { r:0,c:0 }, e : { r:0, c: 0+2-1 }}
   mergeArr.push({s: {r: row, c: col}, e: {r: row, c: col + curHeaderWidth - 1}})

   // 如果子标题还有子标题,就是递归了,要注意更新列数就行
   let tempCol = col
   for (const child of curHeader.children) {
     generateExcelColumn(aoa, row + 1, tempCol, child, mergeArr)
     tempCol += treeWidth(child)
  }
} else {
   // 这里的逻辑就是 如果没有子标题,就正常显示
   // 举个例子,假设整个表头是有三级表头,三级表头也就是有3行,如果第5列是没有任何子级表头的那应该是
   // {s:{r:0,c:5},e:{r:2,c:5}}
   if (row !== aoa.length - 1) {
     mergeArr.push({s: {r: row, c: col}, e: {r: aoa.length - 1, c: col}})
  }
}
}

generateExcelRow


这个函数是根据datasource去生成mergeArr,从mergeArrFn看我们去遍历datasource的每一项,在外层维护rowStartIndex这个变量,我们假设某一项数据的children是一个长度为3的数组,那么通过treeWidth方法(寻找树的宽度)得到的数据就是3,也就是说这一项数据应该占表格3行,但是并不是所有列都是需要3行数据的,所以我们需要去获取到一个不用合并的列prop数组,我们通过这项数据的children的key值去获取,所以这就需要对数据格式有要求了!然后再通过header和getgetLeafProp去获取所有prop,最后遍历判断是否需要去合并行。合并的逻辑是这样的,还是以那个children是一个长度为3的数组为例,如果要合并肯定是3行合并成一行。以第一列为例子,就是 { s : { r : 0, c : 0 }, e : { r : 2 , c : 0 }},下面去遍历props时,下标刚好就是当前的列数。



rowStartIndex 就是从表头的下一行开始


curitem 就是遍历dataSource当前的行


mergeArr 就是mergeArr


header 表头数组



// 合并行
function generateExcelRow(rowStartIndex, curitem, mergeArr, header) {
 // 当前行的高度
 const curHeaderWidth = treeWidth(curitem)
 // 不需要合并的列prop
 const noMerge = (curitem.children && curitem.children.length > 0) ? Object.keys(curitem.children[0]) : []
 // 找到所有prop
 const props = []
 for (const item of header) {
   props.push(...getLeafProp(item))
}
 // 遍历props
 props.forEach((item, index) => {
   // 不是子元素就要合并
   if (!noMerge.includes(item)) {
     mergeArr.push({s: {r: rowStartIndex, c: index}, e: {r: rowStartIndex + curHeaderWidth - 1, c: index}})
  }
})
}

jsonDataToArray


这个函数就是为了生成一个二维数组,因为有子标题,所以可能需要递归。逻辑上也比较简单,假设表头是header,数据源是data,header经过处理后变成了props数组,而data根据props处理后就得到了我们想要的数据。


const header = [
  {
       title: 'a'
       prop: 'aprop'
  },
  {
       title: 'b',
       children:[
          {
               title:'c',
               prop:'cprop'
          },
          {
               title:'d',
               prop:'dprop'
          }
      ]
  },
  {
       title:'e',
       prop:'eprop'
  }
]
const data = [
  {
       aprop:'a1',
       b:{
      cprop:'c1',
      dprop:'d1'
  },
       e:'e1'
  },
  {
       aprop:'a2',
       b:{
      cprop:'c2',
      dprop:'d2'
  },
       eprop:'e2'
  },
]
// 得到的porps
['aprop','cprop','dprop','eprop']

// 最后得到的是这个
[
  ['a1','c1','d1','e1']
  ['a2','c2','d2','e2']
]

getLeafProp其实就是去找所有叶子节点的算法题,recursiveChildrenData就是根据我们得到的props去从data中拿到对应的值,然后如果遇到children就递归去拿,要注意的是就是children要第一条是不要的,children第一条是和这一项数据是一样的。


function jsonDataToArray (header, data) {
 const props = []
 for (const item of header) {
   props.push(...getLeafProp(item))
}
 return recursiveChildrenData(props, data)
}
// 获取叶子节点所有的prop,也就是excel表格每一列的prop
function getLeafProp(root) {
 const result = []
 if (root.children) {
   for (const child of root.children) {
     result.push(...getLeafProp(child))
  }
} else {
   result.push(root.prop)
}
 return result
}
// 从数据中获取对应porps的值
function recursiveChildrenData(props, data) {
 const result = []
 for (const rowData of data) {
   const row = []
   for (const index of props) {
     row.push(rowData[index])
  }
   result.push(row)
   if (rowData.children) {
     result.push(...recursiveChildrenData(props, rowData.children).slice(1))
  }
}
 return result
}

ExcelStyle


这个方法倒是简单,这里其实还可以将表头以及单元格样式抽离出去成为主函数exportExcel的配置项。这个函数干了啥呢,首先就是从columns中拿到每一列的宽度,处理成 ws['!cols']想要的格式,ws['!cols']这个就是sheetJS的配置表格列宽的一个属性。然后就是一些单元格样式,具体去看xslx-js-style的官网。decode_range和encode_cell这两个方法有简单介绍,具体大家去看sheetJS官网吧。



ws 就是 那个表格数据实例


columns 是表头数组


ROW 是表头有多少行


XLSX.utils.decode_range: 用于解析 Excel 工作表中的范围字符串并将其转换为结构化的对象


XLSX.utils.encode_cell:是将一个包含行号和列号的对象编码为 Excel 中常见的单元格地址表示形式



function ExcelStyle (ws, header, ROW) {
 // 列宽
 const widthes = []
 for (const item of header) {
   widthes.push(...getLeafwidth(item))
}
 // 处理成 ws['!cols'] 想要的格式
 const wsCOLS = widthes.map(item => {
   return {
     wpx: item || 100
  }
})
 ws['!cols'] = wsCOLS
 // 定义所需的单元格格式
 const cellStyle = {
   font: { name: '宋体', sz: 11, color: { auto: 1 } },
   // 单元格对齐方式
   alignment: {
     // / 自动换行
     wrapText: 1,
     // 水平居中
     horizontal: 'center',
     // 垂直居中
     vertical: 'center'
  }
}
 // 定义表头
 const headerStyle = {
   border: {
     top: { style: 'thin', color: { rgb: '000000' } },
     left: { style: 'thin', color: { rgb: '000000' } },
     bottom: { style: 'thin', color: { rgb: '000000' } },
     right: { style: 'thin', color: { rgb: '000000' } }
  },
   fill: {
     patternType: 'solid',
     fgColor: { theme: 3, 'tint': 0.3999755851924192, rgb: 'DDD9C4' },
     bgColor: { theme: 7, 'tint': 0.3999755851924192, rgb: '8064A2' }
  }
}
 // 添加样式
 const range = XLSX.utils.decode_range(ws['!ref'])
 for (let row = range.s.r; row <= range.e.r; row++) {
   for (let col = range.s.c; col <= range.e.c; col++) {
     // 找到属性名
     const cellAddress = XLSX.utils.encode_cell({ c: col, r: row })
     if (ws[cellAddress]) {
       // 前几行是表头,添加表头样式
       if (row < ROW) {
         ws[cellAddress].s = headerStyle
      }
       ws[cellAddress].s = {
         ...ws[cellAddress].s,
         ...cellStyle
      }
    }
  }
}
}

// 和getLeafProp类似,只是找的字段不一样
function getLeafwidth(root) {
 const result = []
 if (root.children) {
   for (const child of root.children) {
     result.push(...getLeafwidth(child))
  }
} else {
   result.push(root.width)
}
 return result
}

总结


其实这次也是我第一次自己前端导出excel的需求,之前基本都是后端干的,给个地址直接模拟a标签下载就行了。本来呢,我看项目中也是有封装导出excel的方法的,但是有点晦涩难懂啊,看了下导出的效果,也并不能实现需求。我一直觉得在原有基础的去添加一些相似的功能逻辑,真不如直接重新封装一个方法。然后我测试过了将所有代码赋值到同一个js文件,正常引入传对应的数据结构是能跑通的。其实是有点问题的,就是在根据数据行合并的时候,如果是children里面还children,也就是也要递归,我有点不好拿捏判断递归的时机,加上本来对递归就是一知半解,搞得有点混乱,大家感兴趣的可以试试。


作者:落课
来源:juejin.cn/post/7447368539936587776
收起阅读 »

我二姨卖猪为什么不能自己决定价格

我二姨既养猪也养牛,收益是赔的时候更多。 如果你有投资猪肉股经验,一定知道猪周期。要是在猪肉下行周期中囤猪,那就等着赔吧,赔多少而已。 我年轻的时候就想,为啥二姨自己养的猪,自己却不能决定卖多少价格?多年过去这个问题总算是有点眉目。 本质是二姨在利用市场销售自...
继续阅读 »

我二姨既养猪也养牛,收益是赔的时候更多。


如果你有投资猪肉股经验,一定知道猪周期。要是在猪肉下行周期中囤猪,那就等着赔吧,赔多少而已。


我年轻的时候就想,为啥二姨自己养的猪,自己却不能决定卖多少价格?多年过去这个问题总算是有点眉目。


本质是二姨在利用市场销售自己养的猪,而市场有其自身的规则,单一家庭养猪户是没有办法决定市场猪价的。


一 市场


市场准确的说是市场经济,自我国宋代就已诞生。


然而现代市场经济理论的奠基人是一位西方经济学家——亚当·斯密,就是写了《国富论》的作者。


在《国富论》中其详细阐述了自由市场经济的原理。他提出了“看不见的手”理论,认为在自由竞争的市场中,每个人都在追求自己的利益,这种追求会像一只“看不见的手”一样,引导市场资源向最有利于社会的方向分配。


在姚洋的《经济学的意义》中提到福利经济学第一定律:如果由市场自己去生产和交换,最后经济总会达到帕累托最优。提到福利经济学第二定律:任何的帕累托最优状态,通过调整初始的禀赋分配,最后都能在市场机制下实现。帕累托最优指的是不可能在不牺牲任何人利益的情况下改善其他人的福利的状态。


所以市场经济被认为是配置资源最好的方式,至少目前还没找到比她更好的方式。


曾经一位伟大的国人说,他所做的事情不过是对我们的国家做了一次市场化改革。


现在我们建设的是具有中国特色的市场经济。


二 边际与均衡价格


边际是一种思维方式,就是永远看市场中最后一个人的行为或者最后一个产品的情况。比如在劳动力市场上,工资不是市场中的平均水平的劳动者决定的,而是最后一个参加劳动的人决定的,要看给他多高的工资他才愿意去做这份工作,同时也要看他有多大的贡献工厂才雇用他,两者相等的时候才是市场里的均衡工资。


边际能够解释一些实际问题。比如高速费的收取,如果不收取高速费,会导致高速拥堵,收取高速费导致对高速使用价格敏感者退出,所以说高速价格不是由第一个人决定的,而是最后一些人决定的。


边际也是新商品上市后价格的演化,直到形成均衡价格。就生猪市场而言,其是成熟市场,均衡价格已经形成。在均衡价格下,价格决定于供求关系,决定于价值链,决定于生猪出厂价格和猪肉消费价格。


我的老家在河北,我从我妈那里了解到我们老家农村的猪肉价格是10/斤元上下;而我在北京小区超市看到的是13/斤元上下。这个价格我认为肯定不是大家口袋里没钱造成的。


我又看了下A股几家上规模的生猪养殖集团:牧原股份、温氏股份、正邦科技。三者在2023年都是大幅亏损,其中正邦科技更是st了。而2020年牧原股份大幅度盈利200多个亿,我还查到2020年河北9月份的平均生猪价格,为33.73元/公斤,这都赶上今年的猪肉价了。


这样的数据结果表明今年的猪肉或者生猪价格,主要是供给导致,是生猪太多,生猪养殖太卷,不得不低价销售导致。


总结一下,生猪养殖市场均衡价格由供求关系决定,供求关系就像是天平,只有其上的砝码发生较大变化时才会影响平衡。就生猪市场来说,供求关系可以被牧原股份这种千万生猪体量的养殖集团影响,可以被一场范围特别大的猪瘟影响。


单一家庭养猪户因为生猪体量非常非常小,影响力微乎其微,不可能影响供求关系,也就不可能决定生猪价格,这也就是我二姨不能决定卖猪价格的原因。


三 周期


这部分属于题外话。不仅猪市场存在周期;文明也有周期,表现为王朝的兴衰更替;经济本身也存在周期,比如加息周期和降息周期;现在更有万物皆周期一说。


一种解释是,周期的产生源于人的贪婪。有一句话著名的话:人们从历史中吸取的教训就是从不吸取教训


文明周期源于王朝的后期统治者普遍开始奢侈,导致统治力衰弱,最终王朝灭亡,比如烽火戏诸侯。


经济周期源于债务,也是贪婪。债务越借越大,越借越不想还,就比如现在的美利坚,你看他的国债多大了,一年利息都1w多亿。


或许周期本源于人性,源于这个世界本身,且看那天地有四季,有日月更替。


尾声


现在二姨已经不养猪了。如果还养猪,我会建议要当有大猪场倒闭时再进入,这个时候市场上能卖猪的少了,而想买猪的没变,均衡价格该起来了。


作者:从码农开始
来源:juejin.cn/post/7352100456334639114
收起阅读 »

独立开发:害怕产品被抄袭怎么办?

抄袭是无法避免的,担心被抄袭是很正常的。 大部分情况下,我们要尽量将产品 藏 起来。 其实所谓的 藏,就是 尽量让产品被用户看到,尽量让产品不被同行看到。 那么这个时候呢,我们需要用不为人所知的账号,甚至可以伪装一些个人信息,去产品用户所在的平台进行推广。 藏...
继续阅读 »

抄袭是无法避免的,担心被抄袭是很正常的。


大部分情况下,我们要尽量将产品 起来。


其实所谓的 ,就是 尽量让产品被用户看到,尽量让产品不被同行看到


那么这个时候呢,我们需要用不为人所知的账号,甚至可以伪装一些个人信息,去产品用户所在的平台进行推广。


得好,推广 得好,那这个基本就成了,闷声赚钱吧。


如果没藏住怎么办呢?那就分为 及时雨马后炮 了。


所谓 及时雨,就是不要把鸡蛋放在一个篮子里,狡兔三窟,不要在一根树上吊死,等等。


做多个产品,产生多份收益,把风险分摊。


那么 马后炮 呢,就是看产品的 护城河 有多深了。


也就是说,在产品被同行发现之后,你在这个产品的方向上,跑马圈地,扩展了多大的领土。


具体点来说的话就是,用户交流群有多少,产品社区,产品粉丝有多少。


其中最直观的就是用户交流群,这是你可以用光速传达给用户的最方便,最直接的一个方式。


你可以在群里发挥包括宣传,打压,贬低,超越等方式,来让自己的产品表现得技高一筹,来持续获得用户的青睐。


这是其他竞品短期无法达到的,也是我们自己产品的先发优势和使用惯性。


当然,最终呢,肯定要人无我有,人有我优,才能真正立于不败之地的。


这是适应于大部分产品的策略,记住,是大部分,不是所有。


那么还有另外一部分情况,把产品 住反而不好。


比如你的产品本来就是给同行用的,还藏着掖着怎么行,同行知道得越多越好。


fnMap函数地图


举个例子,我的 VSCode 编辑器插件,fnMap (函数地图),目前已经有 1 万多次安装量,都是我同行,我巴不得知道的人更多一点,安装量越多越好。


问题来了,你不怕同行抄袭吗?


不怕。


为什么呢?这是一个概率问题。


抄袭你作品的人,一定是看过或者用过你作品的人。


这些人里面,对独立开发,对 VSCode 插件开发感兴趣的,不多。


刚兴趣的,有能力开发的,又要少一点。


有能力开发的,有时间,有精力,能坚持开发出来的,又要少一大部分。


能开发出来,能推广运营,能卖出去,能让人付费的,又再少一点。


盈利了,能在微薄的产品收入下,长期维护,更新,完善的人呢,还要再少一点。


总而言之呢,产品的抄袭不是一个 0 到 1 的过程就完事了,它是一个 0-1-100 的过程。


有 99%的人会结束于 99%的进度之前,你的爱好,你的兴趣,你的坚持,就是你最好的防具。


这就好像,你看别人做一个东西赚钱,如果你也抄一个,很有可能别人依旧在赚钱,你就是赚不到钱。


所以,抄袭问题可以担心,但不要过渡担心,用心做产品,就能产生抄袭屏障。


最后呢,产品的公开构建,其实也有好处,可以在项目从开发,到上线,到推广,到运营的过程中持续曝光。


有曝光就有流量,有流量就能产生成交。


很多时候,流量问题,远大于被抄袭的问题。


所以,不用太过于担心产品被抄袭,反而要持续地,不断地,换着花样地,去向全世界分享你的产品。


作者:前端之虎陈随易
来源:juejin.cn/post/7441009356105760803
收起阅读 »

我们领证啦

是的,我们领证了。在跟她经历2年时间的相处后,我们在今天2024年1月5日正式办理了结婚登记。# 我是如何找到老婆的 其实这次还是有那么一点点波折的,因为外地人无法在上海直接领结婚证,但是这个日子是我爷爷请算命先生帮我们看好的,所以我们决定回到我的老家湖北十堰...
继续阅读 »

是的,我们领证了。在跟她经历2年时间的相处后,我们在今天2024年1月5日正式办理了结婚登记。# 我是如何找到老婆的


其实这次还是有那么一点点波折的,因为外地人无法在上海直接领结婚证,但是这个日子是我爷爷请算命先生帮我们看好的,所以我们决定回到我的老家湖北十堰办理结婚登记。


今天请了一天假,考虑到怕一些突发事件,因为我们同省不同市,我怕还要什么证明,我们选择了坐飞机,预留一些时间,比如资料不齐要补资料什么的。因为6点20的飞机,我们定了4.的闹钟,但是凌晨一点半我就醒了,然后一直睡不着,可能是有点小激动的缘故吧。没等闹钟响,我们3点50分起床,煮了2个鸡蛋,带了2盒酸奶,烧了一壶开水装了一杯就匆匆出发了,昨晚预定的出租车4点20也准时到了。到了机场安检才发现不能自带水,酸奶也得喝掉,因为好几年没有坐过飞机了,竟然连这都不知道😂。6点20的飞机,因为晚点,等了一会,大概6点30就起飞了,还好还好,早晨9点就到了武当山机场,晚出发,提前达,这也是可以了。


然后我们打车到民政局,这里有一点小波折,地图一搜随便挑了个,到那发现门口竖了一个牌子,民政局换址了。


图片


我们没办法,只能坐公交去牌子上面民政局的新地址:蓝山郡。到了那里,发现那里是市政府一带,找了好一会才得知,在一个大排档旁边上去的二楼,终于找到了张湾区民政局,忘记拍了,反正非常小的一个门面,仿佛生怕别人找到似的😂。


进了大厅我们发现此时里面只有我们办理,我本来还怕排队。办理的小姐姐人很好,很细心,业务也很熟练,我们提供身-份-证、沪口本、3张照片,期间我们填了2张表,签名,按了6个手印,大概10分钟就办好了。


图片


办理期间我们全程没有表露出很兴奋的表情,以至于出民政局时,我在想当时应该面露开心一点,我甚至觉得自己没有表现好。不过这些都不重要了,此时我们很开心,我们一起走出大厅,我们觉得我们俩此刻是最幸福的人。


总的来看,此次回老家办理结婚登记,整个过程还是挺顺利的。


最后,祝天下有情人终成眷属,希望大家龙年行大运!


作者:大数据技术派
来源:juejin.cn/post/7322355350921461800
收起阅读 »

pnpm v10正式发布,重磅更新,历时3个月,12个版本

web
犹抱琵琶半遮面,千呼万唤始出来,pnpm v10 终于正式发布了。 众所周知,笔者有关注行业技术最新进展的爱好,这次的 pnpm v10 版本,也已经跟踪了好几个月了。 而这次,v10 正式版终于发布了。 版本时间pnpm 10.02025年01月08日pnp...
继续阅读 »


犹抱琵琶半遮面,千呼万唤始出来,pnpm v10 终于正式发布了。


众所周知,笔者有关注行业技术最新进展的爱好,这次的 pnpm v10 版本,也已经跟踪了好几个月了。


而这次,v10 正式版终于发布了。


版本时间
pnpm 10.02025年01月08日
pnpm 10.0 RC 32025年01月05日
pnpm 10.0 RC 22024年12月29日
pnpm 10.0 RC 12024年12月27日
pnpm 10.0 RC 02024年12月16日
pnpm 10.0 Beta 32024年12月12日
pnpm 10.0 Beta 22024年12月09日
pnpm 10.0 Beta 12024年11月29日
pnpm 10.0 Alpha 42024年11月25日
pnpm 10.0 Alpha 32024年11月25日
pnpm 10.0 Alpha 22024年11月15日
pnpm 10.0 Alpha 12024年11月15日
pnpm 10.0 Alpha 02024年10月08日

以上是笔者整理的 pnpm v10 发布过程,从 草案,到 测试版,到 候选版,再到最后的 正式版,可谓是花了不少功夫啊。


也从侧面说明了,pnpm 团队对这次 v10 版本的重视程度,必然是有大事发生,那么话不多说,我们看看本次的更新内容吧。


依赖项的生命周期脚本不会在安装期间执行


这是一个重要变化,依赖包的 生命周期脚本 不会自动执行了。


那么问题来了,可能有些读者还不知道什么是 生命周期脚本生命周期脚本 英文名叫做 Lifecycle scripts


包括以下几种:



  1. 安装相关脚本

    • preinstall:在安装软件包之前执行。

    • install:在安装软件包时执行。

    • postinstall:在安装软件包之后执行。



  2. 发布相关脚本

    • prepare:在发布软件包之前执行。

    • prepublishOnly:只在 npm publish 时执行。

    • prepack:在打包软件包之前执行。

    • postpack:在打包软件包之后执行。



  3. 运行相关脚本

    • prestart/start/poststart:在运行 npm start 时执行。

    • prerestart/restart/postrestart:在运行 npm restart 时执。

    • prestop/stop/poststop:在运行 npm stop 时执行。

    • pretest/test/posttest:在运行 npm test 时执行。




pnpnm v10 开始,这些依赖包中的生命周期脚本都不会自动执行了,这样可以进一步提高安全性。


投票


官方也发起了一个投票:pnpm 可以在安装期间阻止依赖项的生命周期脚本。但这是一个可选功能。我们应该默认阻止它们吗?


最终赞成禁用生命周期脚本的占大多数。


那么我们要让某些依赖包的脚本可以自动执行的话,应怎么做呢?


{
"pnpm": {
"onlyBuiltDependencies": ["fsevents"]
}
}

如上示例,pnpm 提供了一个 onlyBuiltDependencies 参数,所有可以自动执行生命周期脚本的包,都要手动写到里面。


这么一来呢,确实提高了安全性,但是对于开发者来说,也提高了不少复杂性。


因为,可能有些依赖包,或者说依赖包的依赖包,需要自动执行脚本才能生效。


如果采用手动模式,那就很可能很难找到,到底要执行哪个包的生命周期脚本,提高了安全性的同时,也降低了开发的便捷性。


pnpm link 行为更新


这个可能有很多人还没用过,主要用途有 2 个:



  1. 替换已安装的软件包

    • 当你正在开发一个依赖包,想在另一个项目中测试它时,可以使用 pnpm link 将本地版本链接到目标项目。

    • 这样可以避免频繁地发布和安装依赖包,提高开发效率。



  2. 添加全局可用的二进制文件

    • 如果你开发了一个包含命令行工具的软件包,可以使用 pnpm link 将其二进制文件注册到全局,以便在任何地方都可以执行。

    • 这对于开发 CLI 工具非常有用。




那么这次的主要变化有 2 个。



  1. 通过 pnpm link 默认创建的是全局包,在之前,则需要 pnpm link -g 才可以创建全局包。

  2. workspace 的多包项目中,override 被添加到工作区的根目录,将依赖项链接到工作区中的所有项目。


总而言之,就是能全局的就全局,把影响范围扩大化,免得抠抠搜搜的。


可能有读者不知道 override 是啥,这里也科普一下:


假设项目中有两个依赖 A 和 B,它们都依赖于同一个包 lodash,但是需要使用不同的版本。


那么可以使用 overrides 来指定使用 lodash 的特定版本:


{
"dependencies": {
"A": "^1.0.0",
"B": "^2.0.0"
},
"pnpm": {
"overrides": {
"lodash": "^4.17.21"
}
}
}

这样就可以确保项目中使用的 lodash 版本是 4.17.21,而不管 A 和 B 各自需要的版本是什么。


如果某个依赖包存在问题,也可以使用 overrides 来替换它:


{
"dependencies": {
"problem-package": "^1.0.0"
},
"pnpm": {
"overrides": {
"problem-package": "my-forked-package@^1.0.1"
}
}
}

在这个例子中,我们将 problem-package 替换为 my-forked-package 的 1.0.1 版本。


可能我写的文章稍微啰嗦了点,主要是考虑到读者可能存在不同的经验水平,所以一些概念也扩展科普一下。


使用 SHA256 进行安全哈希处理


各种哈希算法已更新为 SHA256,以增强安全性和一致性:



  • node_modules/.pnpm 内的长路径现在使用 SHA256 进行哈希处理。

  • 锁定文件中的长对等依赖关系哈希现在使用 SHA256 而不是 MD5。

  • pnpm-lock.yamlpackageExtensionsChecksum 字段中存储的哈希现在为 SHA256。

  • 副作用缓存密钥现在使用 SHA256。

  • 锁定文件中的 pnpmfile 校验和现在使用 SHA256。


配置更新



  1. manage-package-manager-versions:默认启用。pnpm 现在默认根据 package.json 中的 packageManager 字段管理自己的版本。

  2. public-hoist-pattern:默认情况下不会提升任何内容。名称中包含 eslintprettier 的包不再提升到 node_modules 的根目录。

  3. 已将 @yarnpkg/extensions 升级至 v2.0.3,这可能会改变您的 pnpm-lock 文件。

  4. virtual-store-dir-max-length:Windows 上的默认值已减少到 60 个字符。

  5. 减少脚本的环境变量:在脚本执行期间,会设置较少的 npm_package_* 环境变量。仅保留 nameversionbinenginesconfig

  6. 即使 NODE_ENV=production,所有依赖项现在都会安装。


从现在开始,NODE_ENV=production 也会安装所有依赖,包括开发依赖,这对于像我这样的强迫症来说,有点难以接受,没有用到的依赖我为啥要安装?


查看官方文档,可以通过 pnpm add --prod 来只安装 dependencies 依赖。


全局存储更新



  1. 全局 store 升级到 v10

  2. 一些注册表允许使用不同的软件包名称或版本发布相同的内容。为了适应这种情况,商店中的索引文件现在使用内容哈希和软件包标识符来存储。

    1. 验证锁文件中的完整性是否与正确的包相对应,在 Git 冲突解决不佳后可能并非如此。

    2. 允许相同的内容被不同的包或者同一个包的不同版本引用。



  3. 更高效的副作用索引。存储中的索引文件结构已更改。现在通过仅列出文件差异而不是所有文件,可以更有效地跟踪副作用。

  4. 新的索引目录存储了包内容映射。以前,这些文件位于文件中。


其他重大变化



  • # 字符现在在 node_modules/.pnpm 内的目录名称中被转义。

  • 运行 pnpm add --global pnpmpnpm add --global @pnpm/exe 现在会失败并出现错误消息,指导您改用 pnpm 自我更新。

  • 通过 URL 添加的依赖项现在在锁文件中记录最终解析的 URL,确保完全捕获任何重定向。

  • pnpm deploy 命令现在仅适用于具有 inject-workspace-packages=true 的工作区。引入此限制是为了让我们能够使用工作区锁定文件为已部署的项目创建适当的锁定文件。

  • 删除了从 lockfile v6v9 的转换。如果您需要 v6v9 的转换,请使用 pnpm CLI v9

  • pnpm test 现在将 test 关键字后的所有参数直接传递给底层脚本。这与 pnpm run test 的行为一致。以前您需要使用 -- 前缀。

  • pnpm deploy 现在尝试从共享锁文件创建专用锁文件以进行部署。如果没有共享锁文件或 force-legacy-deploy 设置为 true,它将回退到没有锁文件的部署。


次要变化


添加了对一种名为 configurational dependencie 的新依赖项类型的支持


这些依赖项在所有其他类型的依赖项之前安装 (在 dependenciesdevDependenciesoptionalDependencies 之前)。


配置依赖项不能具有其自身或生命周期脚本的依赖项,应使用精确版本和完整性校验和添加它们。


示例:


{
"pnpm": {
"configDependencies": {
"my-configs": "1.0.0+sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="
}
}
}

新的 verify-deps-before-run 设置


此设置控制 pnpm 在运行脚本之前如何检查 node_modules,有以下值:



  • install:如果 node_modules 已过时,则自动运行 pnpm install。

  • warn:如果 node_modules 已过时,则打印警告。

  • prompt:如果 node_modules 已过时,则提示用户确认运行 pnpm install。

  • error:如果 node_modules 已过时,则抛出错误。

  • false:禁用依赖性检查。


新的 inject-workspace-packages 设置允许对所有本地工作区依赖项进行硬链接,而不是对其进行符号链接。


以前,这可以使用 dependencyMeta[].injected 来实现,现在仍然受支持。


更快的重复安装


在重复安装时,pnpm 会执行快速检查以确保 node_modules 是最新的。


pnpm add 与默认工作区目录集成


添加依赖项时,pnpm add 会检查默认工作区目录。


如果依赖项和版本要求与目录匹配,pnpm add 将使用 catalog: 协议。


如果没有指定版本,它将匹配目录的版本。


如果不匹配,它将恢复为标准行为。


pnpm dlx 解析调整


pnpm dlx 现在将软件包解析为其确切版本,并将这些确切版本用作缓存键。


这可确保 pnpm dlx 始终安装最新请求的软件包。


node_modules 验证


某些命令没有 node_modules 验证,不应修改 node_modules 的命令 (例如 pnpm install --lockfile-only) 不再验证或清除 node_modules。


以上就是本次 pnpm v10 的更新内容,感谢阅读,欢迎点赞,评论和转发。


作者:前端之虎陈随易
来源:juejin.cn/post/7457307617129496614
收起阅读 »

Soul App创始人张璐团队以AI维护网络生态,平台入选“清朗浦江”优秀案例

近日,“清朗浦江·2024网络生态治理总结活动”在上海举行。此次活动由上海市委网信办主办,旨在推广网络综合治理实践经验,推动网络生态向善发展。活动期间,上海市网络协同治理联动机制成员单位、区级网信部门、属地互联网企业等42家单位共选送了74个案例,经过层层遴选...
继续阅读 »

近日,“清朗浦江·2024网络生态治理总结活动”在上海举行。此次活动由上海市委网信办主办,旨在推广网络综合治理实践经验,推动网络生态向善发展。活动期间,上海市网络协同治理联动机制成员单位、区级网信部门、属地互联网企业等42家单位共选送了74个案例,经过层层遴选,最终评选出15个优秀案例。其中,Soul App创始人张璐团队的“AI大模型助力技术创新,精准识别让虚假人设无处遁形”案例成功入选。

作为本次活动的亮点之一,此次活动的优秀案例是由上海网络清朗小卫士——“沪小信”来发布。“沪小信”是由上海互联网信息办公室出品的代表形象,自2020年诞生以来,它一直以1.0动画版的形象出现。2024年,在Soul的帮助下,“沪小信”迎来了2.0数字人版本的升级。有了SoulX多模态大模型赋能,“沪小信”实现了与观众的实时互动,进一步增强了公众对网络治理工作的理解和参与。

通过本次活动的案例展示,可以看出,网络生态治理已经成为当前社会发展的重要议题。近年来,针对年轻用户群体的网络诈骗手段日益复杂化,网络空间的治理也不能再仅仅依赖传统手段。在此背景下,Soul其风控和画像团队在技术创新方面展开了深度探索。他们研发的“虚假人设报警模型”基于AI大模型技术,能够通过多维度的数据分析,快速识别出虚假身份,提升平台的治理效率。

通过精准的数据筛查和行为分析,系统不仅能够检测到虚假信息,还能够追踪到涉及欺诈、诈骗等不法行为的用户,并发出风险预警。Soul团队利用这一技术,有效保障了平台社交空间的真实与安全,帮助用户在社交过程中避开“假人设”陷阱。

“清朗浦江·2024”网络生态治理优秀创新案例的发布,不仅展示了上海在推动网络生态健康发展方面的工作成果,也体现了技术创新在网络治理中的重要作用。本次活动突出强调了营造清朗的网络空间是社会各界共同努力的目标,也是推动网络强国建设的重要内容。在这一过程中,Soul始终秉承“真诚社交”的理念,持续强化平台的技术建设和网络治理,注重在技术研发和用户安全上的投入,推动平台在用户互动的真实性与安全性上不断优化。

此次Soul入选“清朗浦江·2024”网络生态治理优秀创新案例,意味着Soul App创始人张璐团队在网络治理方面的努力获得了更多认可。通过提升技术手段和治理能力,Soul创始人张璐团队不仅为用户提供了一个更安全、更真实的社交平台,也为网络生态的健康发展注入了新的动力。

收起阅读 »

极客公园创新大会探索AI未来,Soul App创始人张璐团队以技术驱动创新

2024年12月,极客公园创新大会2025在北京举行,吸引了来自科技行业的众多专家和企业代表。在这场以“敢想,敢干!Imagineering”为主题的盛会中,Soul App作为社交领域的创新代表,受邀参与并分享了其在人工智能社交领域的探索和实践。大会期间,S...
继续阅读 »

2024年12月,极客公园创新大会2025在北京举行,吸引了来自科技行业的众多专家和企业代表。在这场以“敢想,敢干!Imagineering”为主题的盛会中,Soul App作为社交领域的创新代表,受邀参与并分享了其在人工智能社交领域的探索和实践。大会期间,Soul App创始人张璐团队与一众业内人士共同探讨了AI技术如何赋能社交。

在大会的“新世界 New Things·New World”环节,Soul App CTO陶明深入阐述了Soul团队在AI社交领域的最新进展,以及平台在推动智能社交新时代方面的思考。他分享道,根据数据显示,2024年Soul平台用户高频搜索的关键词之一便是“AI苟蛋”。作为拟人化的智能聊天机器人,“AI苟蛋”能够为用户提供情绪价值,其受欢迎的现象也充分体现了用户对AI虚拟陪伴的强烈兴趣。从某种程度上,这一趋势验证了AI社交与平台生态的深度融合。

AI技术的发展正在重新定义社交平台的互动方式。年轻一代对“人机关系”的理解正在重构,他们对于交互效率、体验和对象的认知正在变化。Soul旗下Just So Soul研究院发布的《2024 Z世代AIGC态度报告》数据显示,超过六成的年轻人认为AIGC产品可以在一定程度上缓解孤独感,三分之一的年轻人期待与AI“做朋友”。“AI社交时代已经到来”,陶明进一步表示。

作为新型开放式社交平台,Soul从上线起便注重在社交中引入智能化元素。平台迅速推出了自研引擎,通过分析用户画像和兴趣图谱,以流量普惠的方式实现了人与人、人与内容的智能连接。2020年,Soul开始了在AIGC领域的布局,陆续推进在智能对话、语音技术、3D虚拟人等多个领域的技术积累。至今,Soul已先后上线了自研的语言大模型Soul X,以及语音生成、语音识别、语音对话、音乐生成等多项语音大模型能力。

2024年,Soul的AI大模型能力进一步升级为多模态端到端大模型,支持文字对话、语音通话、多语种、多模态理解等功能,能够实现更自然的日常交互,为用户提供“类真人”情感陪伴。

通过对AI技术的深度布局,Soul团队不仅在产品创新上取得了显著进展,也在用户活跃度和平台粘性方面取得了可观的成果。据陶明透露,Soul平台的AI功能推出以来,用户的日均活跃时长和互动频率均有所提升。

作为深受年轻人欢迎的社交网络平台,Soul App创始人张璐团队始终坚持以用户为中心,积极回应用户的需求和反馈,不断迭代更新产品功能。在深入探索AI与社交融合的同时,Soul通过大模型赋予用户更多的情感支持,为用户打造出更智能、更具情感连接的社交平台。

收起阅读 »

我不允许还有人不知道前端实现时刻洪水模拟的方法!🔥

web
二维水动力 HydroDynamic2D 二维水动力介绍 二维水动力模型对象 HydroDynamic2D,基于真实数据驱动生成水动力模型(根据不同时刻下每个网格的流向、流速、高程、水位) 二维水动力模型考虑了水流在平面上的变化,适用于河道弯曲、水流方向多变的...
继续阅读 »

二维水动力 HydroDynamic2D


二维水动力介绍


二维水动力模型对象 HydroDynamic2D,基于真实数据驱动生成水动力模型(根据不同时刻下每个网格的流向、流速、高程、水位)


二维水动力模型考虑了水流在平面上的变化,适用于河道弯曲、水流方向多变的情况。这种模型能够更准确地反映水流在平面上的分布情况,适用于需要精确模拟水流动态的场景,如城市排水系统设计、洪水模拟。二维模型的优势在于能够提供更详细的水流信息,但计算复杂度较高,需要更多的计算资源和时间。


二维水动力效果2.gif

本篇文章主要介绍在DTS 数字孪生引擎中实现二维水动力效果。在DTS SDK中开放了 HydroDynamic2D对象 添加二维水动力,并可以通过多种数据源进行添加,如 Bin、Sdb、Shp、Tif 的方式。


本文章主要介绍shp加载的方式,这种方式相对其他方式会更简单通用。


shp数据源添加方式


所需数据源


二维水动力是用数据驱动生成渲染效果的接口,所以数据源及其重要。


要利用shp为数据源进行添加,使用的是addByShp()方法,其与数据源相关的参数有两个:shpFilePath shpDataFilePath


shpFilePath其实就是水动力模型中水面网格的范围与高程,shpDataFilePath则代表每个网格的水深以及流速、流向



  • shpFilePath: 添加二维水动力模型整体范围的shp文件路径,取值示例:"C:/shpFile/xxx.shp"。



    • 此shp文件包含水动力模型所有网格的范围

    • shp类型为Polygon

    • 坐标系必须与工程坐标系保持一致

    • 必须包含 ID和Elev 两个字段:ID是网格ID;Elev是网格的高程值,单位是米




image-20241216172254779.png

  • shpDataFilePath: 可选参数,仅在update()方法执行生效。更新二维水动力模型时包含水面网格的dat类型文件路径,取值示例:"C:/datFile/xxx.dat"。

  • dat文件是一种二进制文件,它提取了某一时刻包含的所有水面网格的信息,并把这些信息依次写入了二进制文件dat。

  • 一个水面网格信息包含如下一组四个值:id (int),h (double),u(double),v(double),必须完全符合顺序以及数据类型。

  • id对应shp属性表ID字段,h是网格对应的水深(单位是米),uv是流速和流向(单位米/秒,u朝东,v朝北)。

  • 更新效果需要准备多个时刻的.dat文件,如下图所示

    image-20241216172314255.png


添加方法


1、准备测试数据

这里给大家准备好了一些数据资源,包括了实现的数据源、代码以及dat数据转换的程序,大家可以自行下载测试



百度网盘数据资源连接:pan.baidu.com/s/1XS3UDkrB…




  • 【文件资源】@path : 放到cloud文件资源路径

  • 【示例代码】code : demo源代码,直接用demo工程场景运行即可

  • 【dat数据转换】jsonToDat : json转dat代码,分别含有node.js、java、python示例代码


准备好两份数据分别是shpFilePath填写的shp文件,以及shpDataFilePath填写的dat文件集。文件可以直接用本地路径读取,建议放置到Cloud文件资源路径下,用@path的方式引用


这里可以用孪创启航营给大家准备的数据进行测试,在提供的文件夹的【文件资源】@path\【孪创启航营】HydroDynamic2D


2、通过shp网格数据初始化水动力模型

通过add()初始化水动力模型,并使用focus()定位到网格位置,但没有具体内容,还需要调用update添加.dat数据驱动效果。


add()参数文章末尾有详解


//添加shp数据源
fdapi.hydrodynamic2d.clear()

let hydrodynamic2d_add = {
id: 'hdm_shp', // HydroDynamic2D对象ID
collision: false, //开启碰撞sd
displayMode: 0, // 显示样式,取值范围:[0,1],0水体样式(默认值),1热力样式
waterMode: 0, // 水面显示模式,枚举类型 0 水动画模式 ,1水仿真模式,2 水流向模式
arrowColor: [1, 1, 1, 0], // 箭头颜色和透明度
speedFactor: 0.1, // 速度因子
rippleDensity: 1, // 水波纹辐射强度
rippleTiling: 3, // 水波纹辐射平铺系数
shpFilePath: '@path:【孪创启航营】HydroDynamic2D/shp/grid.shp' // 添加二维水动力模型整体范围的shp文件路径
}
await fdapi.hydrodynamic2d.add(hydrodynamic2d_add)

await fdapi.hydrodynamic2d.focus('hdm_shp', 200)

3、根据.dat更新水动力模型

写一个定时器,根据不同时刻,调用hydrodynamic2d.update()更新shpDataFilePath路径,达到水动力更新的效果。



  • 参数updateTime 是更新动画的插值时间,单位为秒,一般与更新定时器的时间一致即可。


let index = 0
let hydrodynamicModel_for_update = {
id: 'hdm_shp', // HydroDynamic2D对象ID
updateTime: 1, // 更新动画的插值时间
shpDataFilePath: ''// 更新二维水动力模型时包含水面网格的dat类型文件路径
}

// 使用dat数据填充shp网格
let updateTimer = setInterval(async () => {
hydrodynamicModel_for_update.shpDataFilePath = '@path:【孪创启航营】HydroDynamic2D/dat/hydrodynamic_' + index + '.dat'

if (index > 9) {
clearInterval(updateTimer)
} else {
await __g.hydrodynamic2d.update(hydrodynamicModel_for_update) // 水动力更新
index = index + 1
}
}, 1000)

通过以上就可以达成二维水动力的创建以及更新了。


4、实现二维水动力热力效果

二维水动力支持热力效果,可以根据.dat文件中的水深字段进行配色


二维水动力热力效果.gif

仅需要把add()中的displayMode参数设置为1热力样式,再通过valueRangecolors进行热力样式的调整



  • valueRange (array) ,二维水动力模型颜色插值对应的数值区间

  • colors (object) 二维水动力模型自定义调色板对象,包含颜色渐变控制、无效像素颜色和调色板区间数组



    • gradient (boolean) 是否渐变

    • invalidColor (Color) 无效像素点的默认颜色,默认白色

    • colorStops (array) 调色板对象数组,每一个对象包含热力值和对应颜色值,结构示例:[{"value":0, "color":[0,0,1,1]}],每一个调色板对象支持以下属性:

      • color (Color) 值对应的调色板颜色

      • value (number) 值




    const addHeat = async () => {
    fdapi.hydrodynamic2d.clear()

    let hydrodynamic2d_add = {
    id: 'hdm_shp_heat', // HydroDynamic2D对象ID
    offset: [0, 0, 0], // 二维水动力模型的整体偏移,默认值:[0, 0, 0]
    displayMode: 1, // 显示样式,取值范围:[0,1],0水体样式(默认值),1热力样式
    waterMode: 2, // 水面显示模式,枚举类型 0 水动画模式 ,1水仿真模式,2 水流向模式
    arrowColor: [1, 1, 1, 0.5], // 箭头颜色和透明度
    collision: false, //开启碰撞sd
    arrowTiling: 3, // 箭头平铺系数
    speedFactor: 0.1, // 速度因子
    rippleDensity: 1, // 水波纹辐射强度
    rippleTiling: 2, // 水波纹辐射平铺系数
    shpFilePath: '@path:【孪创启航营】HydroDynamic2D/shp/grid_heat.shp',

    valueRange: [1, 1.3], // 二维水动力模型颜色插值对应的数值区间
    alphaMode: 1, //使用colors色带透明度
    colors: {
    gradient: true,
    invalidColor: [0, 0, 0, 1],
    colorStops: [
    {
    value: 0,
    color: [0, 0, 1, 0.2]
    },
    {
    value: 0.25,
    color: [0, 1, 1, 0.2]
    },
    {
    value: 0.5,
    color: [0, 1, 0, 0.2]
    },
    {
    value: 0.75,
    color: [1, 1, 0, 0.2]
    },
    {
    value: 1,
    color: [1, 0, 0, 0.2]
    }
    ]
    }
    }
    await fdapi.hydrodynamic2d.add(hydrodynamic2d_add)

    await fdapi.hydrodynamic2d.focus('hdm_shp_heat', 200)

    let index = 0
    let hydrodynamicModel_for_update = {
    id: 'hdm_shp_heat',
    updateTime: 1,
    shpDataFilePath: ''
    }

    //使用dat数据填充shp网格
    let updateTimer = setInterval(async () => {
    hydrodynamicModel_for_update.shpDataFilePath = '@path:【孪创启航营】HydroDynamic2D/dat/hydrodynamic_' + index + '.dat'

    if (index > 9) {
    clearInterval(updateTimer)
    } else {
    await __g.hydrodynamic2d.update(hydrodynamicModel_for_update)
    index = index + 1
    }
    }, 1000)
    }



demo运行


缺乏数据源的小伙伴可以尝试运行我们准备好的demo示例,感受一下水动力的效果与参数调用。



  1. **下载资源:**下载百度网盘数据资源

  2. 替换资源:把【文件资源】@path的文件放到cloud文件资源路径下

  3. **启动cloud:**cloud启动demo工程

  4. 替换sdk:【示例代码】code\lib\aircity中的ac.min.jsac.min.js,替换为cloud右上角"sdk"路径的对应文件

  5. **运行:**双击运行示例代码】code\二维水动力.html 代码里的 shpFilePathshpDataFilePath路径得和第2步中一致


二维水动力效果1.gif

.dat 数据转换?


在数据源中,网格对应的水深、流速、流向数据,大家获取到可能不是标准的dat数据,有可能是json、csv甚至是excel数据。所以这里教大家如何把常见的数据转为dat二进制文件!


大象进冰箱需要三步,咱们转数据也需要三步



  1. 解析数据:读取文件,把不同数据源中的id,h,u,v(网格id、水深、流速流向u、流速流向v)提取出来。

  2. 转为二进制数据:把id,h,u,v转化为二进制的格式。

  3. 文件创建并写入:把二进制的格式数据保存为.dat文件


其中解析数据每份数据可能各不相同,都需要单独编写。这里我以一个json数据格式为例子,教大家如何转换为.dat,例如我们有一个data.json文件数据示例如下:


[
{
"index": 0,
"time": "08:30:00",
"data": [
{
"id": 0,
"h": 2,
"u": 0,
"v": 0
},
{
"id": 1,
"h": 2,
"u": 0,
"v": 0
}
]
},
{
"index": 1,
"time": "09:00:00",
"data": [
{
"id": 0,
"h": 2,
"u": 0,
"v": 0
},
{
"id": 1,
"h": 2.001,
"u": 0.1,
"v": 0.1
}
]
}
]


我们可以使用不同的编程手段来处理,如node.js、python、java,这里直接把转换的代码贴给大家~


注意:这三种编程手段都需要单独的安装对应的环境,如果没有环境可以选择一种自行百度安装



node官网:Node.js — 在任何地方运行 JavaScript


python官网:python.org


java官网:Java | Oracle



node.js


  1. 解析数据:使用require('./data.json')同步地引入并解析JSON数据文件,将其内容存储在jsonData变量中。

  2. 转为二进制数据:pamarToBuffer函数将idhuv转换为小端字节序的二进制Buffer。

  3. 文件创建并写入:遍历JSON数据,对每个时间点,使用path.join构建.dat文件路径,fs.createWriteStream创建写入流,datStream.write写入二进制Buffer,最后datStream.end关闭写入流。


// 引入必要的模块
const fs = require('fs') // 用于文件的读写操作
const path = require('path') // 用于处理文件路径
const jsonData = require('./data.json') // 引入 JSON 数据文件

// 确保 ./dat 目录存在
const datDir = path.join(__dirname, 'dat')
if (!fs.existsSync(datDir)) {
fs.mkdirSync(datDir)
}

// 遍历 JSON 数据 time_i 是当前时间点的索引
for (let time_i = 0; time_i < jsonData.length; time_i++) {
// 创建 .dat 文件路径
const datFilePath = path.join(datDir, `hydrodynamic_${time_i}.dat`)
// 创建写入流
const datStream = fs.createWriteStream(datFilePath)

// 获取并遍历时间点的数据
const timeData = jsonData[time_i].data
for (let grid_i = 0; grid_i < timeData.length; grid_i++) {
// 数据转换和写入
const { id, h, u, v } = timeData[grid_i]
const buffer = pamarToBuffer(id, h, u, v)
datStream.write(buffer)
}

datStream.end()
}

function pamarToBuffer(id, h, u, v) {
// 创建一个 Buffer 来存储二进制数据
const buffer = Buffer.alloc(4 + 8 + 8 + 8) // 分配足够的空间:4 字节用于 id,3 个 8 字节用于 double 值
// 向 Buffer 中写入数据
buffer.writeInt32LE(id, 0) // 从索引 0 开始写入 id(32 位整数)
buffer.writeDoubleLE(h, 4) // 从索引 4 开始写入 h(64 位浮点数)
buffer.writeDoubleLE(u, 12) // 从索引 12 开始写入 u(64 位浮点数)
buffer.writeDoubleLE(v, 20) // 从索引 20 开始写入 v(64 位浮点数)

return buffer
}


python


  1. 解析数据:使用json.load(f)方法从打开的JSON文件对象f中读取并解析数据,将JSON格式的数据转换为Python的字典或列表结构,存储在变量json_data中。

  2. 转为二进制数据:使用struct.pack('=iddd', id, h, u, v)方法将这些数据按照指定的格式(=表示本地字节顺序,i表示整数,d表示双精度浮点数)打包成二进制数据。

  3. 文件创建并写入:使用open函数以二进制写入模式打开(或创建)文件,最后通过write方法将转换好的二进制数据写入到该文件中。


import json
import os
import struct

# 读取JSON文件
json_file_path = './data.json'
with open(json_file_path, 'r') as f:
json_data = json.load(f)

# 定义输出目录
output_dir = os.path.join(os.getcwd(), 'dat')
if not os.path.exists(output_dir):
os.makedirs(output_dir)

# 遍历JSON数据
for time_i, time_node in enumerate(json_data):
# 创建.dat文件路径
dat_file_path = os.path.join(output_dir, f"hydrodynamic_{time_i}.dat")

# 打开文件以二进制写入模式
with open(dat_file_path, 'wb') as dat_file:
# 获取并遍历时间点的数据
time_data = time_node['data']
for grid_i, data_element in enumerate(time_data):

# 数据转换和写入
id = int(data_element['id'])
h = float(data_element['h'])
u = float(data_element['u'])
v = float(data_element['v'])

# 使用struct模块将数据转换为二进制格式
binary_data = struct.pack('=iddd', id, h, u, v)
# 写入二进制数据到文件
dat_file.write(binary_data)

print("Data processing complete.")

Java

java需要安装对应的 jackson json解析依赖才能使用,这里给大家提供了一个最简洁的版本,只需要有了对应的java环境运行目录下的start.bat文件即可生成dat文件。



  1. 解析数据:使用ObjectMapperdata.json文件中读取JSON数据,并解析为TimePoint对象的列表。

  2. 转为二进制数据:convertToBytes方法将TimePointData对象的idhuv字段转换为小端字节序的字节数组。

  3. 文件创建并写入:遍历TimePoint列表,为每个时间点创建.dat文件,并使用FileOutputStream将转换后的字节数组写入文件。


import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

class TimePointData {
int id;
double h;
double u;
double v;

public TimePointData(int id, double h, double u, double v) {
this.id = id;
this.h = h;
this.u = u;
this.v = v;
}

}

class TimePoint {
List<TimePointData> data;

public TimePoint(List<TimePointData> data) {
this.data = data;
}

}

public class JsonToDatConverter {

public static void main(String[] args) {
String jsonFilePath = "data.json";
String datDir = "dat";

// 读取JSON文件
ObjectMapper objectMapper = new ObjectMapper();
try {
JsonNode rootNode = objectMapper.readTree(Files.newInputStream(Paths.get(jsonFilePath), StandardOpenOption.READ));
List<TimePoint> timePoints = parseJsonToTimePoints(rootNode);

Path dirPath = Paths.get(datDir);
if (!Files.exists(dirPath)) {
Files.createDirectory(dirPath);
}

for (int time_i = 0; time_i < timePoints.size(); time_i++) {
TimePoint timePoint = timePoints.get(time_i);
String datFilePath = Paths.get(datDir, "hydrodynamic_" + time_i + ".dat").toString();

try (FileOutputStream fos = new FileOutputStream(datFilePath)) {
for (TimePointData data : timePoint.data) {
byte[] bytes = convertToBytes(data.id, data.h, data.u, data.v);
fos.write(bytes);
}
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}

private static List<TimePoint> parseJsonToTimePoints(JsonNode rootNode) {
if (rootNode == null || !rootNode.isArray()) {
throw new IllegalArgumentException("Invalid JSON structure: 'timePoints' field is missing or not an array");
}

List<TimePoint> timePoints = new ArrayList<>();
for (JsonNode timePointNode : rootNode) {
JsonNode dataNode = timePointNode.get("data");
if (dataNode == null || !dataNode.isArray()) {
throw new IllegalArgumentException(
"Invalid JSON structure: 'data' field is missing or not an array within a 'timePoints' object");
}

List<TimePointData> dataList = new ArrayList<>();
for (JsonNode dataItemNode : dataNode) {
int id = dataItemNode.get("id").asInt();
double h = dataItemNode.get("h").asDouble();
double u = dataItemNode.get("u").asDouble();
double v = dataItemNode.get("v").asDouble();
dataList.add(new TimePointData(id, h, u, v));
}

timePoints.add(new TimePoint(dataList));
}

return timePoints;
}

private static byte[] convertToBytes(int id, double h, double u, double v) {
ByteBuffer buffer = ByteBuffer.allocate(4 + 8 + 8 + 8).order(ByteOrder.LITTLE_ENDIAN);
buffer.putInt(id);
buffer.putDouble(h);
buffer.putDouble(u);
buffer.putDouble(v);
return buffer.array();
}
}

二维水动力添加参数详解


通用参数

通用参数比较简单理解,这里就简单列举出来



  • id (string) HydroDynamic2D对象ID

  • groupId (string) 可选,Gr0up分组

  • userData (string) 可选,用户自定义数据

  • offset (array) 二维水动力模型的整体偏移,默认值:[0, 0, 0]

  • collision (boolean) 是否开启碰撞,注意:开启后会影响加载效率


数据参数

数据参数前面介绍所需数据源已有详细介绍



  • shpFilePath(string)添加二维水动力模型整体范围的shp文件路径,取值示例:"C:/shpFile/xxx.shp"。

    • 此shp文件包含水动力模型所有网格的范围

    • shp类型为Polygon

    • 坐标系必须与工程坐标系保持一致

    • 必须包含 ID和Elev 两个字段:ID是网格ID;Elev是网格的高程值,单位是米



  • shpDataFilePath (string)可选参数,仅在update()方法执行生效。更新二维水动力模型时包含水面网格的dat类型文件路径,取值示例:"C:/datFile/xxx.dat"。

    • 注意:dat文件是一种二进制文件,它提取了某一时刻包含的所有水面网格的信息,并把这些信息依次写入了二进制文件dat,一个水面网格信息包含如下一组四个值:id,h,u,v。id对应shp属性表ID字段(int类型),h是网格对应的水深(double类型,单位是米),uv是流速和流向(double类型,单位米/秒,u朝东,v朝北)。




显示样式参数


  • displayMode (number) 显示样式,取值范围:[0,1],0水体样式(默认值),1热力样式



    • displayMode为0时,样式就只需要控制waterModewaterColor设置水体样式



      • waterMode (number) 水面显示模型,枚举类型 0 水动画模式 ,1水仿真模式,2 水流向模式

      • waterColor (Color) 水体颜色和透明度,注意:仅在displayMode=0时生效



    • displayMode为1时,样式就需要通过valueRangecolors控制热力样式



      • valueRange (array) ,二维水动力模型颜色插值对应的数值区间

      • colors (object) 二维水动力模型自定义调色板对象,包含颜色渐变控制、无效像素颜色和调色板区间数组



        • gradient (boolean) 是否渐变

        • invalidColor (Color) 无效像素点的默认颜色,默认白色

        • colorStops (array) 调色板对象数组,每一个对象包含热力值和对应颜色值,结构示例:[{"value":0, "color":[0,0,1,1]}],每一个调色板对象支持以下属性:

          • color (Color) 值对应的调色板颜色

          • value (number) 值





      • colors代码示例


        // colors示例
        {
        gradient: true,// 是否渐变
        invalidColor: [0, 0, 0, 1],// 无效像素点的默认颜色
        colorStops: [
        {
        value: 0,
        color: [0, 0, 1, 1]
        },
        {
        value: 0.25,
        color: [0, 1, 1, 1]
        },
        {
        value: 0.5,
        color: [0, 1, 0, 1]
        },
        {
        value: 0.75,
        color: [1, 1, 0, 1]
        },
        {
        value: 1,
        color: [1, 0, 0, 0]
        }
        ]
        }






  • alphaComposite (boolean) 是否使用混合透明度 取值:true / false 默认:true

  • alphaMode (number) 透明模式,取值:[0,1],0 : 使用colors调色板的不透明度值 1 : 使用系统默认值


箭头相关参数

箭头方向根据每个格网的uv流向决定



  • arrowDisplayMode (number) 箭头显示模式 取值范围:[0,1],0默认样式(受arrowColor参数影响),1热力样式(受arrowColors调色板参数影响)



    • arrowDisplayMode 为0,则设置arrowAlphaMode = 0,并通过arrowColor调整箭头的颜色和透明度

      • arrowColor (Color) 箭头颜色和透明度



    • arrowDisplayMode 为1,则设置arrowAlphaMode = 1,并通过arrowColors调整箭头的颜色和透明度

      • arrowColors (object)箭头颜色调色板 仅在arrowDisplayMode=1时生效,河道箭头热力样式下的调色板配色对象,包含颜色渐变控制、无效像素颜色和调色板区间数组

        • 格式同上方的显示样式参数colors







  • arrowAlphaMode (number) 箭头透明度模式,仅在arrowDisplayMode=0时生效,取值:[0,1],0使用arrowColor的透明度,1使用调色板的透明度

  • arrowTiling (number) 箭头平铺系数 值越小则箭头越小越密集,反之则更大更疏松


箭头.png
水面效果参数


  • foamWidth (number) 泡沫宽度取值范围:[0~10000],默认值:1米

  • foamIntensity (number) 泡沫强度 取值范围:[0~1],默认值:0.5

  • speedFactor (number) 速度因子


速度因子.gif

  • flowThreshold (array) 水浪效果漫延的范围 即把水动力模型[minSpeed,maxSpeed],最小最大流速的范围映射到[0~~1],取值示例:[0.1,0.4],取值范围[0-1]


水浪效果漫延的范围.png

  • rippleDensity (number)水波纹辐射强度


水波纹辐射强度.gif

  • rippleTiling (number) 水波纹辐射平铺系数


水波纹辐射平铺系数.gif


以上就是本篇文章的所有内容,相信大家看完这篇文章后可以轻松的通过DTS实现二维水动力效果。


在DTS中还有各式各样的水分析相关接口,如FloodFill 水淹分析、Fluid 流体仿真对象、HydroDynamic1D 一维水动力、WaterFlowField 水流场,大家可以根据自身需求选择,这里给大家推荐一篇《开闸放水》的教程,后续也会陆续推出更多教程~


不再需要UE美术,前端轻松解决水利开闸放水难题!!!


作者:女前端浅入数字孪生
来源:juejin.cn/post/7452181029994971147
收起阅读 »

神了,Chrome 这个记录器简直是开发测试提效神器🚀🚀🚀

web
在开发工作中,你是否遇到过这样的场景: 当你需要开发某个功能时,这个功能依赖一系列的点击或者选择操作,才能获取到最终的数据。而在开发和调试的过程中,你往往需要多次验证流程的正确性。早期的时候,这种验证通常非常繁琐——你可能需要反复提交表单、重新执行操作流程,才...
继续阅读 »

在开发工作中,你是否遇到过这样的场景:


当你需要开发某个功能时,这个功能依赖一系列的点击或者选择操作,才能获取到最终的数据。而在开发和调试的过程中,你往往需要多次验证流程的正确性。早期的时候,这种验证通常非常繁琐——你可能需要反复提交表单、重新执行操作流程,才能完成一次完整的自测。


如今,这一切变得更加高效了。


现在,我们可以使用记录器(Recorder)来优化这一开发流程。这个工具允许你将整个操作过程录制下来,保存为一个可复现的操作记录。每次需要重新验证或提交流程时,只需一键执行这条记录,便能完成所有的重复性操作。


更棒的是,这个功能还支持二次编辑。如果你需要在某个步骤后面新增额外的操作,或者减少不必要的步骤,都可以轻松修改操作记录,而无需重新录制整个流程。



文章同步在公众号:萌萌哒草头将军,欢迎关注哦~



🚀 功能亮点与用途


1. 高效的开发与调试


对于开发者来说,这个功能不仅可以节省大量时间,还能确保操作流程的准确性,避免因手动操作而导致的遗漏或错误。


2. 性能监控的得力助手


谷歌推出这个功能的主要目的是为了帮助开发者更方便地监听用户在某些操作流程中的性能体验。例如,在查看录制的操作流程时,你可以直接点击某个步骤,跳转到性能面板(Performance Panel),并且工具会自动锁定当前帧的数据。这种体验优化相比以往手动查找性能问题,提升了不少效率。


3. 测试自动化的天然工具


如果你是一名测试人员,这个功能同样非常实用。操作流程录制完成后,你可以直接将其导出为Puppeteer脚本,方便地将其集成到你的自动化测试中,进一步提升测试的覆盖率和效率。


🚀 使用方法


我们以表单提交为例子展示


image.png


以下是如何使用记录器功能的步骤:


1. 💎 打开记录器


image.png


并点击创建新录制按钮


image.png


2. 💎 开始录制流程


可以重命名下,方便后续复用,然后点击最下方的开始录制按钮


image.png


我们在填写完表单,并且点击 sumbit按钮,然后点击控制台的结束录制按钮,可以看到我们的每个步骤都被记录下来


image.png


3. 💎 执行录制



  1. 记录器 面板中,点击 播放 按钮,浏览器会自动按照录制的流程重新执行操作。

  2. 你可以在执行过程中观察页面行为,确认流程是否正确。

  3. 如果遇到下面的情况,说明是超时了,需要设置下超时时间


image.png


点击这个地方展开就可以重新设置超时限制参数了


image.png


然后你点击播放按钮就一切正常了


nalmal.gif


4. 💎 查看和编辑录制


你可以在 记录器 面板中,看到录制的每个步骤,包含操作类型(如点击、输入、导航等)和目标元素。


你也可以点击每个步骤进行详细查看,也可以通过右键菜单进行编辑,例如增加新步骤、删除步骤或修改操作。


🚀 应用场景


1. 💎 表单提交及验证


录制复杂的表单提交流程,方便反复验证数据的提交逻辑是否正确。这个场景如上,相信你也感受它的便利性了。


2. 💎 性能优化


在模拟用户真实操作的同时,快速捕捉性能瓶颈,定位问题并优化。


点击性能面板按钮,等待自动回填数据,然后跳到性能面板,为了压缩我把很多帧去掉了


preform.gif


最终你可以在如下的性能面板开始分析了


353.png


3. 💎 自动化测试开发


如果需要将录制的流程用于自动化测试,可以点击 导出 按钮,将其导出为 Puppeteer 脚本或者 json数据,这样可以减少编写测试脚本的时间,通过导出的 Puppeteer 脚本直接复用操作流程。我不是测试人员就不多赘述了。


🚀 小结


“记录器”功能的出现,不仅让开发和调试更加高效,还为性能监控和测试自动化提供了重要支持。它减少了重复操作的浪费,让开发者和测试人员都能将更多精力集中在核心工作上。


是不是觉得这个功能非常有趣又实用?赶紧试试看吧!


如果有用记得关注我的公众号:萌萌哒草头将军


作者:萌萌哒草头将军
来源:juejin.cn/post/7447456628284244005
收起阅读 »

4点起床不一定行,但早睡早起很可以

最近快速读完了《4点起床》这本书。 这本书很简单,主要内容就是为什么要4点起床、如何做到4点起床和起床后要做什么。 整体上给它打 3 颗星,可读可不读那种。 而这本书是我买其他书时,凑单顺手买的,目前已经挂在多抓鱼上卖掉了。 那为什么还是给大家分享呢?主要是...
继续阅读 »

截屏2024-10-10 17.28.12.png


最近快速读完了《4点起床》这本书。


这本书很简单,主要内容就是为什么要4点起床、如何做到4点起床和起床后要做什么。


截屏2024-10-10 16.36.30.png


整体上给它打 3 颗星,可读可不读那种。


而这本书是我买其他书时,凑单顺手买的,目前已经挂在多抓鱼上卖掉了。


那为什么还是给大家分享呢?主要是它提供了一种生活方式。


几年前听说过日本留行过一阵“朝忙族”,指的是那些,选择早上早起工作,而不是晚上加班的人群。查看这本书的出版时间,正好是那个时候,可以确定这本书与这阵风潮有一定关系。


如今这股潮流已经过去,但这也说明了一些问题。毕竟对于大多数人来说,凌晨四点起床确实非常艰难。


不过,书中提倡的早睡早起理念,我还是很推荐的。在这里分享几点对我触动较大的内容。


为什么选择早起干活,而不是晚上加班干活


很多上班族有一个习惯:晚上加班才能完成任务。然而,作者更提倡早起干活,因为这是由人类的生理规律决定的。


事实上,研究表明大脑在下班后会逐渐进入休息状态,而早起则能够充分利用身体中荷尔蒙的激活,从而完成这些事情更轻松。


写作也是如此。虽然一些创作者可能认为灵感是他们工作的关键,但许多欧美作家已经开始提倡将写作日常化,使用具体方法来进行写作,而不是仅仅依靠灵感。中国也有不少作家开始模仿这一做法,例如已完成多部畅销小说的马伯庸先生,他每年完成几部小说,其著作量远超同行。


我个人观点认为,晚上工作的人往往需要一个没人打扰的环境,而早上同样可以实现这一目标。


我曾经问过一些早睡早起的朋友,他们都说有过一种平静的喜悦,这种感觉很难用言语描述,也许是来自于长期规律生活的多巴胺。我个人也是如此,在一段早睡早起的时间后,感到一种特殊的满足感。如果你也想尝试这种感觉,我建议你至少持续一个月(甚至更久)的早睡早起。


早起之后做什么?


早起之后可以进行哪些活动?


享用一顿营养均衡的早餐是必不可少的,这有助于确保一整天的精神饱满。如果你是有家庭的人,与家人共度一段早餐时光,还能够增进家庭成员之间的情感联系。


书中还提到很多建议都围绕着输入和输出的。例如,多读书、多写作等。虽然直接开始大量输出对许多人来说可能有些困难,但其实每天记录一些日志会更加可行。


这里所说的“日志”并非传统的个人日记,而是指一种记录日常活动的笔记形式。


通过撰写日志,您可以总结前一天所做的事情,并为当天制定详细的计划清单。明确哪些任务是重要的,哪些是非做不可的。这样做有助于您更好地管理自己的时间与工作安排,确保每一天都有条不紊地进行,有利于你告别无意义感和瞎忙的状态。


此外,这样的习惯还有助于推进那些重要但并非紧急的任务,避免它们被忽视或延误。


早起后,是否应该获取信息


早起后,是否应该获取信息?


自人类进入现代文明以来,报纸、收音机、电视和互联网的出现使得人们进入了信息过载的时代。如果我们仍然像以前一样被动地接收信息,最终只会接收到大量无用的信息。


书中提出的一个观点我认为颇有参考价值,即批判性阅读新闻。例如,在阅读股市财经类新闻时,应当质疑股价与该新闻的相关性。


当然,这种做法对个人的要求似乎较高,需要每次都能动用自己的大脑进行思考。


我个人的做法更为彻底,我删除了所有的新闻应用程序,甚至包括抖音在内的所有字节系应用。这些应用的推送机制非常奇怪,故意模糊了时间点,导致你看到的可能是几年前的旧闻。后来,许多应用都采用了类似的推送方式。


因此,我干脆屏蔽了所有的新闻客户端。


有人可能会问,那你的新闻资讯从哪里获取呢?实际上,在日常生活中,自然会有同事,在茶歇或饭间,讨论重要的新闻事件,所以根本不用担心自己会错过重要信息。


熬夜怎么办?


程序员熬夜.jpeg


书中关于应对熬夜的方法,我个人觉得非常有参考价值。


我们都知道,作为程序员或白领,偶尔熬夜在所难免,而一次熬夜可能会导致接下来两到三天内精神状态不佳,感觉昏昏沉沉。


书中提供了一个很好的方法:如果知道自己要熬夜,可以先睡3个小时,然后再起来继续熬夜。这种方法能在一定程度上缓解因熬夜带来的负面影响。


这本书相关的内容就讲这么多。剩下的大部分都是讲职场的作者个人分享,不适合我,我感受也不深。所以就分享到这里。


谢谢大家的观看。


作者:陈佬昔的编程人生
来源:juejin.cn/post/7423944621720354842
收起阅读 »

程序员就得会偷懒,重写了一个electron小工具,解放美女运营老师!

web
前言 接前一篇美女运营天天找我改配置,给她写了个脚本,终于安静了 之前只是写了一个脚本,本地运行,通过读取文件流获取文件数据,格式化对应数据,运营老师也不会安装node,还是需要我去操作。现在我用electron生成一个桌面应用直接生成后复制json,去配置,...
继续阅读 »

前言


接前一篇美女运营天天找我改配置,给她写了个脚本,终于安静了


之前只是写了一个脚本,本地运行,通过读取文件流获取文件数据,格式化对应数据,运营老师也不会安装node,还是需要我去操作。现在我用electron生成一个桌面应用直接生成后复制json,去配置,全程不需要我参与了。


之前的脚本


const fs = require('fs')
const csv = require('csv-parser');

const csvfilePath = './xxx.csv';
const uidsfilePath = './uids.json';

const results = [];
let newarr = [];
let lineCount = 0;

fs.createReadStream(csvfilePath)
.pipe(csv({ headers: true }))
.on('data', (data) => {
results.push(data);
lineCount++;
})
.on('end',async () => {
console.log(results[0])
await format(results);
fs.writeFile(uidsfilePath, JSON.stringify(newarr), () => {
console.log('done')
})
});
const format = (results) => {
newarr = results.map(item => {
if(item._0 === 'key' || item._1 === 'value') {
return {}
}
return {
label: `${item._1}-${item._0}`,
value: item._1
}
})
}

electron


简介


Electron 是一个用于使用 JavaScript、HTML 和 CSS 构建跨平台桌面应用程序的框架。它由 GitHub 开发,基于 Chromium 和 Node.js。这意味着开发者可以利用他们熟悉的 Web 开发技术来创建桌面应用。


优势



  • 跨平台开发

  • 快速开发迭代

  • 丰富的生态系统


架构与核心概念



  • 主进程和渲染进程:


主进程:主进程是整个 Electron 应用的核心,它负责创建和管理应用程序的窗口。主进程通过BrowserWindow模块来创建浏览器窗口,这个窗口就是用户看到的应用界面的载体。


渲染进程:渲染进程主要负责渲染应用的用户界面。每个BrowserWindow都有自己独立的渲染进程,它使用 Chromium 浏览器内核来解析 HTML 和 CSS 文件,执行 JavaScript 代码。



  • 进程间通信(IPC):
    由于 Electron 应用有主进程和渲染进程之分,进程间通信就显得尤为重要。Electron 提供了ipcMain(用于主进程)和ipcRenderer(用于渲染进程)模块来实现进程间的消息传递。


使用vue3和vite创建vue的项目然后引入electron


安装vite


npm create vite@latest electron-desktop-tool

安装 引入electron&插件


npm install -D electron // electron
npm install -D electron-builder //用于打包可安装exe程序和绿色版免安装exe程序
npm install -D electron-devtools-installer // 调试
npm install -D vite-plugin-electron // vite构建插件

创建主进程


在vue 同级src目录下,创建src-electron 文件夹 新建main.js


// src-electron/main.js
const { app, BrowserWindow } = require('electron')
const { join } = require('path')

// 屏蔽安全警告
// ectron Security Warning (Insecure Content-Security-Policy)
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'

// 创建浏览器窗口时,调用这个函数。
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
title: 'electron-vite',
// icon: join(__dirname, '../public/logo.ico'),
})

// win.loadURL('http://localhost:3000')
// development模式
if(process.env.VITE_DEV_SERVER_URL) {
win.loadURL(process.env.VITE_DEV_SERVER_URL)
// 开启调试台
win.webContents.openDevTools()
}else {
win.loadFile(join(__dirname, '../dist/index.html'))
}
}

// Electron 会在初始化后并准备
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})

app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})

配置插件入口


在vite.config.ts中配置vite-plugin-electron 插件入口


import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import electron from 'vite-plugin-electron'

// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
electron({
// 主进程入口文件
entry: './src-electron/main.js'
})
],
/*开发服务器选项*/
server: {
// 端口
port: 3000,
}
})

配置package.json


在package.json 新增入口文件 "main": "./src-electron/main.js",


原神启动 emmm electron启动


运行 npm run dev 启动项目


请在此添加图片描述


打包配置


首先配置一下打包的命令,在package.json "scripts"里面配置这个打包命令


  "scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"postinstall": "patch-package",
"electron:build": "vite build && electron-builder",
"pack32": "vite build && electron-builder --win --ia32",
"pack64": "vite build && electron-builder --win --x64"
},

同样package.json 需要添加打包配置


  "scripts": {
...
},
"build": {
"productName": "ElectronDeskTopTool",
"appId": "dyy.dongyuanwai",
"copyright": "dyy.dongyuanwai © 2024",
"compression": "maximum",
"asar": true,
"directories": {
"output": "release/"
},
"nsis": {
"oneClick": false,
"allowToChangeInstallationDirectory": true,
"perMachine": true,
"deleteAppDataOnUninstall": true,
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"shortcutName": "ElectronDeskTopTool"
},
"win": {
"icon": "./public/logo.ico",
"artifactName": "${productName}-v${version}-${platform}-setup.${ext}",
"target": [
{
"target": "nsis"
}
]
},
"mac": {
"icon": "./public/logo.ico",
"artifactName": "${productName}-v${version}-${platform}-setup.${ext}"
},
"linux": {
"icon": "./public/logo.ico",
"artifactName": "${productName}-v${version}-${platform}-setup.${ext}"
}
},

然后npm run electron:build


请在此添加图片描述


页面效果


请在此添加图片描述


github地址


后续还会继续更新~


作者:一起重学前端
来源:juejin.cn/post/7445289957893259327
收起阅读 »

悲惨!刚入职没几天,无意间把数据库删了,很尴尬,原因很奇葩

1. offer收割机,就职新公司 5年前的就业环境非常好,当时面试了很多家公司,收到了很多 offer。最终我决定入职一家互联网教育公司,新的公司福利非常好,各种零食随便吃,据说还能正点下班,一切都超出我的期望,“可算让我找着神仙公司了”,我的心里一阵窃喜。...
继续阅读 »

1. offer收割机,就职新公司


5年前的就业环境非常好,当时面试了很多家公司,收到了很多 offer。最终我决定入职一家互联网教育公司,新的公司福利非常好,各种零食随便吃,据说还能正点下班,一切都超出我的期望,“可算让我找着神仙公司了”,我的心里一阵窃喜。


在熟悉环境之后,我趁着上厕所的时候,顺便去旁边的零食摊挑了点零食。接下来的一天里,我专注地配置开发环境、阅读新人文档,当然我也不忘兼顾手边的零食。


入职几天后 ,领导给安排了一个小需求,我和同事沟通完技术方案后,就开始开发了。


2. 单元测试有点奇怪


完成开发后,我决定写个单元测试验证下,在研究单元测试代码后,我发现这种单测写法和我之前的写法不太一样。


这家公司的单测好像没有启动整个项目,仅加载了部分类,而且不能访问测试环境数据库~ 于是我决定按照前东家写单测的方式重新写单元测试。


于是我新增了一个单测基类,在单测中启动整个SpringBoot,直接访问测试环境数据库。然而也并不是很顺利,启动阶段总是会遇到各种异常报错,需要一个一个排查…… 所幸项目排期不紧张,还有充足时间。


我做梦也没有想到,此刻,已经铸成大错。


3. 故障现场


我身边的工位旁慢慢地聚集了越来越多的人,本来我还在安安静静的调试单元测试,注意力不自觉的被吸引了过去。


“测试环境为什么这么多异常,访问不通啊。到处都是 500 报错”,不知道谁在说话。


“嗯,我们还在排查,稍等一下”,我旁边的同事一边认真排查日志,一边轻声回复道。


“为什么数据库报的异常是, 查不到数据呢?” ,同事在小声嘀咕,然后打开 命令行,立即登上 MySQL。


我亲眼看着他在操作,奇怪的是数据库表里的数据全部被删掉了,其他的几个表数据也都被删除了。


简直太奇怪了,此刻的我还处于吃瓜心态。


有一个瞬间我在考虑,是否和我执行的单元测试有关系? 但我很快就否决掉了这个想法,因为我只是在调试单元测试,我没有删数据库啊,单测里也不可能删库啊。 我还在笑话自己 胡思乱想……


很快 DBA 就抱着电脑过来,指着电脑说,你们看这些日志,确实有人把这些表删除了。


"有 IP 吗,定位下是谁删除的, 另外线上环境有问题吗?”,旁边的大组长过来和 DBA 说。


“嗯,我找到ip 了,我找运维看下,这个ip是谁的”。DBA 回复道。


4. 庭审现场


当 DBA 找到我的时候,我感到无辜和无助,我懵逼了,我寻思我啥也没干啊,我怎么可能删库呢。 (他们知道我刚入职,我现在怀疑:那一刻他们可能会怀疑 我是友商派过来的卧底、间谍,执行删库的秘密任务)


经过一系列的掰扯和分析,最终定位 确实是我新增的单元测试把数据库删了。


5. 故障原因


需要明确的是,原单元测试执行时不会删除数据库;测试环境启动时也不会删除数据库。


只要在单元测试中连接测试数据库,就会删除掉数据库的所有数据。为什么呢?


5.1 为什么单元测试删除了所有数据?


原单元测试 使用的是 H2 内存数据库,即Java 开发的嵌入式(内存级别)数据库,它本身只是一个类库,也就是只有一个 jar 文件,可以直接嵌入到项目中。H2数据库又被称为内存数据库,因为它支持在内存中创建数据库和表。所以如果我们使用H2数据库的内存模式,那么我们创建的数据库和表都只是保存在内存中,一旦应用重启,那么内存中的数据库和表就不存在了。 所以非常适合用来做单元测试。


H2 数据库在启动阶段,需要执行用户指定的 SQL 脚本,脚本中一般包含表创建语句,用来构建需要使用的表。


但是我司的 SQL 脚本除了创建表语句,还包含了删除表语句。即在创建表之前先删除表。 为什么呢? 据他们说,是因为这个 SQL 脚本可能会重复执行,当重复执行时创建表语句 会报错。所以他们在创建表之前,先尝试删除表。这样确保 SQL 脚本可重复执行。( 其实可以用 Create if not exists )


故障的原因就是:测试数据库执行了这个删表再建表的 SQL 脚本,导致所有数据都被清除了。


5.2 为什么测试数据库会执行这条 SQL 脚本呢?


1) 我新建的单元测试把H2 内存数据库换成了测试数据库。


2) spring.data.initialize=默认值为 true; 默认情况下,会自动执行 sql 脚本。


所以测试数据库 执行了 SQL 脚本。


5.3 为什么在测试环境正常启动时,没有问题,不会删除所有数据呢?


只有单测引入测试数据库才会出问题,在测试环境正常启动项目是没问题的。


当编译项目时,测试目录下的文件、代码和正式代码编译后的结果不会放到一起。因为 SQL脚本被放在了 测试目录下, 所以正式代码在测试环境启动时,不会执行到这个 SQL脚本,自然不会有问题。


image.png


6. 深刻教训


最终数据被修复了,DBA有测试数据库的备份,然而快照并非实时的,不可避免地还是丢失了一部分数据。


所幸的是出问题的是测试环境,并非线上环境。 否则,我会不会被起诉,也未可知。


后续的改进措施包括



  1. 收回了数据库账户的部分权限,只有管理账户才可以修改数据库表结构。代码中执行 DML语句的账户不允许执行 DDL 语句。

  2. DBA 盘点测试数据库的快照能力,确保快照间隔足够短,另外新增一个调研课题:删库后如何快速恢复,参照下其他公司的方案。

  3. 所有的项目 spring.data.initialize 全部声明为 false。不自动执行 SQL 脚本

  4. SQL脚本一律不许出现 删除表的语句。SQL不能重复执行的问题,想其他办法解决。

  5. 另外的一个项目急需人手,把新来的那谁 调到其他项目上


这可能是程序员们在技术上越来越保守的原因……不经意的一个调整可能引发无法承受的滔天巨浪


作者:五阳
来源:juejin.cn/post/7412490391935893541
收起阅读 »

antd 对 ai 下手了!Vue 开发者表示羡慕!

web
前端开发者应该对 Ant Design 不陌生,特别是 React 开发者,antd 应该是组件库的标配了。 近年来随着 AI 的爆火,凡是想要接入 AI 的都想搞一套自己的 AI 交互界面。专注于 AI 场景组件库的开源项目倒不是很多见,近日 antd 宣布...
继续阅读 »


前端开发者应该对 Ant Design 不陌生,特别是 React 开发者,antd 应该是组件库的标配了。


近年来随着 AI 的爆火,凡是想要接入 AI 的都想搞一套自己的 AI 交互界面。专注于 AI 场景组件库的开源项目倒不是很多见,近日 antd 宣布推出 Ant Design X 1.0 🚀 ,这是一个基于 Ant Design 的全新 AGI 组件库,使用 React 构建 AI 驱动的用户交互变得更简单了,它可以无缝集成 AI 聊天组件和 API 服务,简化 AI 界面的开发流程。


该项目已在 Github 开源,拥有 1.6K Star!



看了网友的评论,看来大家还是需要的!当前的 Ant Design X 只支持 React 项目,看来 Vue 开发者要羡慕了...



ant-design-x 特性



  • 🌈 源自企业级 AI 产品的最佳实践:基于 RICH 交互范式,提供卓越的 AI 交互体验

  • 🧩 灵活多样的原子组件:覆盖绝大部分 AI 对话场景,助力快速构建个性化 AI 交互页面

  • ⚡ 开箱即用的模型对接能力:轻松对接符合 OpenAI 标准的模型推理服务

  • 🔄 高效管理对话数据流:提供好用的数据流管理功能,让开发更高效

  • 📦 丰富的样板间支持:提供多种模板,快速启动 LUI 应用开发

  • 🛡 TypeScript 全覆盖:采用 TypeScript 开发,提供完整类型支持,提升开发体验与可靠性

  • 🎨 深度主题定制能力:支持细粒度的样式调整,满足各种场景的个性化需求


支持组件


以下圈中的部分为 ant-design-x 支持的组件。可以看到主要都是基于 AI Chat 场景的组件设计。现在你可以基于这些组件自由组装搭建一个自己的 AI 界面。



ant-design-x 也提供了一个完整 AI Chat 的 Demo 演示,可以查看 Demo 的代码并直接使用。



更多组件详细内容可参考 组件文档


使用


以下命令安装 @ant-design/x 依赖。


注意,ant-design-x 是基于 Ant Design,因此还需要安装依赖 antd


yarn add antd @ant-design/x

import React from 'react';
import {
// 消息气泡
Bubble,
// 发送框
Sender,
} from '@ant-design/x';

const messages = [
{
content: 'Hello, Ant Design X!',
role: 'user',
},
];
const App = () => (
<div>
<Bubble.List items={messages} />
<Sender />
</div>

);

export default App;

Ant Design X 前生 ProChat


不知道有没有小伙伴们使用过 ProChat,这个库后面的维护可能会有些不确定性,其维护者表示 “24 年下半年后就没有更多精力来维护这个项目了,Github 上的 Issue 存留了很多,这边只能尽量把一些恶性 Bug 修复



如上所示,也回答了其和 Ant Design X 的关系:ProChat 是 x 的前生,新用户请直接使用 x,老用户也请尽快迁移到 x


感兴趣的朋友们可以去试试哦!


作者:五月君
来源:juejin.cn/post/7444878635717443595
收起阅读 »

30岁,我开启了人生副业

我有工作,我还在写代码,大家别再重复问了😭😭😭 大家好,我是朽木白,一名非常普通的前端程序员,在前端这条路上淌七年的浑水,毫无建树。在互联网泡沫的末法时代,不得已换了一份工作,自降6k去了一家教育公司,由于个人原因,在今年的三月份我决定辞职。当时辞职后的第一...
继续阅读 »

我有工作,我还在写代码,大家别再重复问了😭😭😭



大家好,我是朽木白,一名非常普通的前端程序员,在前端这条路上淌七年的浑水,毫无建树。在互联网泡沫的末法时代,不得已换了一份工作,自降6k去了一家教育公司,由于个人原因,在今年的三月份我决定辞职。当时辞职后的第一想法是再换个公司继续干前端,正好是金三银四,可能行情好一点。很显然,现实给了我狠狠的一个大逼兜。在我辞职之前,我粉丝群的500个道友们都劝我苟住,不要任性,我没听劝,非要看看怎么个事。准备好了面试题,写好了简历,开始投递,结果一投一个不吱声。要么是未读,要么是已读不回,要么是不合适(岗位是资深、专家、架构师),唯一回复的都是外包,薪资只有十几k,心高气傲的我也是一口回绝。找了半个月,心气彻底凉了。这时候我想着打工已经不是很好的选择了,心里落差很大,于是决定创业。


在之前,我也在创业的路上进行过尝试。主要是面试辅导。在职的时候我就给粉丝修改简历,辅导面试,因此也收获了很多粉丝,大家给面子,都亲切的叫一声白哥。至于现在为什么放弃了呢?当时白天上班,抽空给粉丝看看简历,晚上回家腾讯会议一对一的指导如何修改简历,并且一直都是免费的。后面我又在某音开直播,在直播间连线粉丝,有任何问题都可以问的那种。还有一个收费的就是面试辅导,针对每个人不同的情况进行辅导,给他们指导项目,修改简历,每天晚上讲解面试题,划重点,面试复盘等等。如果不在公司加班(加班一般都是11点才能下班,到家都12点多了),晚上回家的任务就是看简历,辅导学员。因为当时全部都是我自己一个人干,没有任何团队,也没有和任何人合作过,也没有接过任何第三方广告。干了一个月,我遭不住了,身心疲惫。除了收获了一批忠实的粉丝,钱基本没有挣到多少。这时候我已经陷入了一种困境和迷茫的状态。我到底要不要继续坚持下去,我的这种付出到底能给我带来啥,更多的是给我带来的一些焦虑和内耗,尤其是一些粉丝找工作的现状,惨不忍睹,我看着也跟着心急。后来我就索性不干了,在群里活跃气氛,跟大家扯扯皮,聊聊八卦(我摆烂了),创业宣告失败。


接下来就是第二次创业了,在失业的这两月当中,我合伙跟别人开了一家眼镜店,目前已经正常运营。因为我媳妇是内行,所以开起来非常的顺利。我的身份也从一名前端程序员转变成了一名眼镜从业人员。跨度非常大,因为此前我从未接触过这个行业。简单讲讲开店的过程吧。涉及到金额方面的我就不提了。


第一选开店的地址,在北京的这四九城里转悠了一周多,看了好多地方,地段有好有坏,房租有高有低。我选择店铺的依据根据这几个方面来,交通方便,周围上班族、学校多,人流大,周围2KM没有同行,租金一万左右的底商为主。最终我选择了靠近霍营地铁站的一个商铺,距离不过500m。


image.png


第二店铺装修,找熟人,省了不少钱。装修也是要考虑很多,眼镜柜的各种尺寸要测量标准,因为上面要加装玻璃柜,严丝合缝,不能有偏差。还有柜台的设计,各个机器的摆放要合理的腾出位置,因为店铺的面积不是很大,空间要合理利用起来。还有其他的一些柜子,眼镜的摆放等等都是有学问的,没有经验的人来根本干不了一点。
这是装修完完刚收拾的样子


image.png
这是柜台


image.png


第三进货,货主要有三种,镜片,镜框,仪器。这些都是在潘家园眼镜城那边有厂家可以拿货。因为我媳妇之前是开店的,她有认识的人脉资源,进货的时候都是她带着去挑。进货花钱是大头,尤其是那些机器,更先进了,也更贵了。机器会有专门的安装人员上门安装调试。眼镜摆好了,机器调试好了,差不多就可以开业,我的店是05.17正式开业的,在没有开业之前就已经有人来配眼镜了,所以我开业提前了几天。
开业了


image.png


现在开了差不多半个多月了,差不多每天都能开张,时不时也能来个大单,虽然没有我上班每个月挣的多了,但是没有那么累了,因为眼镜店一天人流量没那么大,一天能进店五六个人就够了,所以我有很多时间干自己想干的事情,比如拍拍短视频,写写技术文章,学学自己之前没有来得及学的技术,我依然热爱代码。当然开眼镜店最重要的是为顾客配一副戴着舒适的眼镜,人家才会信任你,帮你带新,回购,因为眼镜这个东西很多人一旦配了一次很舒服的,下次就认准你了,别的店他不信任。


目前生活状态:已经入职新公司,还是继续写代码,不加班,不打卡,没有倒排期,没有PUA,按时发工资。店铺一切经营正常。希望我的这个店能一直开下去,红红火火。


最近好多不在北京的粉丝反馈,让我做个小程序,可以直接查看店里的眼镜,他们可以挑选心仪的镜框,方便线上配镜。目前小程序正在开发中,大家敬请期待!


作者:白哥学前端
来源:juejin.cn/post/7377001684159774760
收起阅读 »

什么黑科技?纯血鸿蒙又可以运行Android应用了!

背景 纯血鸿蒙OS Next系统最近出现了两款热门应用:出境易、卓易通,其功能是:让你在出境后可以方便安装到各种Android应用。 发生了什么? 「出境易」这款应用可以在纯血鸿蒙OS NEXT里直接安装&运行Android应用! 纯血鸿蒙官方声...
继续阅读 »


背景


纯血鸿蒙OS Next系统最近出现了两款热门应用:出境易、卓易通,其功能是:让你在出境后可以方便安装到各种Android应用




发生了什么?


「出境易」这款应用可以在纯血鸿蒙OS NEXT里直接安装&运行Android应用!



纯血鸿蒙官方声称:「不支持运行Android应用」!



于是:



  • 很多正在努力开发、兼容纯血鸿蒙应用的开发者都在议论:是不是可以停鸿蒙开发、继续写回Android了?

  • 也有很多粉丝后台私信Carson,问:目前继续学鸿蒙开发到底还有没意义






本文意图


今天Carson来带大家扒扒「出境易」、「卓易通」到底是怎么能在纯血鸿蒙OS NEXT里运行Android应用的。具体包括:「出境易」、「卓易通」这两款Android应用



  1. 在纯血鸿蒙系统里运行的底层支持是什么?

  2. 在纯血鸿蒙系统里的运行环境是什么?

  3. 「出境易」、「卓易通」本质是什么?

  4. 在「出境易」、「卓易通」上的Android应用性能、体验如何?




问题1:在纯血鸿蒙系统里运行的底层支持是什么?



  • 无论黑科技有多 “黑”,总需要底层给与相关支持才有运行的可能。

  • 在初次安装「出境易」、「卓易通」时需下载一个环境,抓包&解包可得到:



其中最为关键的文件:anco_hmos.img,从字面解释来看:



  • anco:AndroidCompatible = 安卓兼容

  • hmos:HarmonyOS = 鸿蒙OS系统

  • 整体看,即**「鸿蒙OS系统里的安卓兼容」**


实际上,这其实是一个安卓镜像文件,是一个嵌入到鸿蒙OS系统层面的安卓运行环境(类似虚拟机的作用,但实际不是虚拟机)。



其实是类似wsl技术,即Windows Subsystem for Linux = Windows的Linux子系统,能让开发者在Windows操作系统中直接运行Linux环境,而无需任何虚拟机。



所以,要在纯血鸿蒙OS 上安装「出境易」、「卓易通」不仅需要下载很大的安卓镜像资源包,还需要重启系统,因为「出境易」和 「卓易通」是单独的“运行环境”。


值得一提的是:



  • 因为本身鸿蒙OS内核就兼容了Linux ABI(应用程序二进制接口),即鸿蒙OS内核本身就可以运行为Linux设计的应用。

  • 所以,虽然这是一个安卓镜像,但这个属于鸿蒙的安卓镜像并没有包含Linux 内核,只是包含运行时(Runtime)部分。 以下是鸿蒙内核架构图:
    鸿蒙内核示意图




问题2:在纯血鸿蒙系统里的运行环境是什么?


那么,这类Android应用到底是运行在什么环境上的呢?打开「出境易」内的app后,通过执行shell ps -ef会出现以下进程:



  • 即其运行环境是:通过lxc-start命令启动了一个基于iSulad的容器的进程。

  • iSulad 是华为自研的容器引擎,是一个非常通用的容器引擎,具有轻、快、 易、灵的特点。以下是其架构图:



iSulad官网介绍:http://www.openeuler.org/zh/other/pr…






问题3:「出境易」、「卓易通」本质是什么?



二者的功能都是:让你在出境后可以方便安装到各种app。听起来是不是有点类似国内的应用商店



  • 实际上,二者在鸿蒙next商店下载的是一层壳,负责与纯血鸿蒙OS进行权限交互(图片、文件IO等)

  • 本体也是Android应用的apk,即出境易.apk、卓易通.apk。拿出来也是可以在Android手机上安装的。(如下图)


除此以外,「出境易」还含有一个「文件共享.apk」、「卓易通」还有一个「搜应用.apk」、「文件共享.apk」。


这里值得一提的是,两个“应用商店”可搜到的应用原理不同:



  • 出境易:白名单方式,即只有与其合作的Android应用可以安装;

  • 卓易通:黑名单方式,即只有纯血鸿蒙OS上架的应用不可以安装;


下面附上视频:纯血鸿蒙OS 「出境易」、「卓易通」安装Android应用实机演示



http://www.bilibili.com/video/BV1Q9…





性能如何?


既然能跑了,那么用户体验如何呢?网友们已经开始跑分了:



  • 测试环境:麒麟9000s;

  • 结论:单核心正常跑分1000,目前「出境易」是930分左右,效率是93%;




  • 分析:上面提到其底层支持是类似wsl的技术,同时运行环境是采用华为自研的iSulad 容器引擎的方式,并非所谓的虚拟机环境。这种嵌入方式可以使得安卓应用能够在鸿蒙系统上运行,但又不会占用过多的资源或影响系统的稳定性

  • 结合业界常见容器水平93%左右,华为的iSulad容器达到了业界水平,可理解为:GPU性能几乎无损。


但是对于内存使用就不太友好了,容器本身内存占用极大,基本一个容器进程就是8GB,随便开两个应用12GB就没了。

同时结合网上使用的评价:手机容易发烫(功耗高)、应用Bug较多等等,可以总结为:以这种方式在纯血鸿蒙OS上运行的Android应用 「能用」,但是「不好用」,与原生体验还是存在很大差距




结论



  • 技术角度 分析:基于anco_hmos,采用类似wsl的方式同时结合iSulad容器引擎,使得在纯血鸿蒙OS上运行Android应用成为了板上钉钉的现实

  • 性能角度 实践:在CPU性能可认为几乎无损的情况下,内存跟功耗问题短时间内还是无法解决;

  • 用户体验 观察:应用Bug较多,结合性能内存问题,目前暂时仅处于一个**「能用」**的状态。


基于上述分析 & 问题表现,在纯血鸿蒙OS上运行Android应用在国内大范围使用短时间内几乎不可能,更多的是在一些小众、边缘、尝试探索的场景,比如一些使用频率较低的小众app、尝试出海境外的场景(如本文提到的「出境易」等)


最后


如何看待这次在纯血鸿蒙OS上运行Android应用的事件呢?评论区留言你的看法!


参考文章:



作者:Carson带你学Android
来源:juejin.cn/post/7448576110823047202
收起阅读 »

我的 2024 年终总结

2024 年,我离开了待了两年的互联网公司,来到了一家聚焦教育机器人和激光切割机的公司,没错,是一家硬件公司,从未接触过的领域,但这还不是我今年最重要的里程碑事件 5 月份的时候,正式提出了离职,没有骑驴找马,完全裸辞。对于 gap 的这段时间,做了简单的规划...
继续阅读 »

2024 年,我离开了待了两年的互联网公司,来到了一家聚焦教育机器人和激光切割机的公司,没错,是一家硬件公司,从未接触过的领域,但这还不是我今年最重要的里程碑事件


5 月份的时候,正式提出了离职,没有骑驴找马,完全裸辞。对于 gap 的这段时间,做了简单的规划,先去旅游一趟,然后用一个半个月时间备考雅思,九月、十月重新找工作


随后的两个月,公司找到接替我的新同学,站好最好一班岗,跟同事做了告别。7 月 5 号,拿着离职证明,收拾好东西,离开了西丽。隔天就参加 VueConf 大会,见到了尤雨溪和 Anthony Fu




做了这么多年精神股东,终于来支持一回,希望 React 越办越好 👏



VueConf 结束之后,就去流放岭南,在广西桂林,体会到了什么叫做“江作青罗带,山如碧玉簪”



这里的山水真的很美,养得蚊子珠圆玉润,也感受到喀斯特地貌对于经济发展的阻碍,拔地而起的峭壁山峰,割裂了交通,住房和经济


在去到九马画山的偏方小路上,看到一路上种植着柚子,玉米等等,这是属于亚热带季风气候的回馈,光照充足,雨水充沛,水果种植,也成了当地人除旅游业之外的另一条生计


这一次是 p 人之旅,没有特种兵定点打卡,而是更多感受地理,人文。嗦了三天的桂林米粉之后,又回到了深圳,开启了雅思备考


关于考雅思,一个是本身对英语感兴趣,另一个是看过许多老前辈的经验之谈,学好英语对于程序员职业发展来说,是长期利好的事情


在这段时间,还学会做饭,个人以为,做饭和编程一样,都是属于创造的艺术


心血来潮还买了一个小米空气炸锅,第一次用觉得超级神奇的,仅仅依靠空气就能够把鸡米花烤得 tree tree 的



接下来的一个半月的时间,把自己当成高考生,按部就班地学习



8 月 30 号早上踏入考场,上午听力阅读写作,下午口语。成绩出得很快,三天后如期而至,得到了一个非常低的分数,这给了我当头一棒


付出了大量的时间精力,并不意味着有美好的收获,我花了三天时间做了痛苦而又深刻的复盘,是能力基础问题?是自律问题?是备考策略问题?是心态问题?最后结论是出来的是备考策略出现重大失误,罔顾实际情况,按照自己天真烂漫的想法去复习



复盘这几天我似乎有点“龙场悟道”,这个“道”后来我把它总结了「成长型思维」,关于成长型思维具象表现是,对于雅思考试的折戟失败,我没有消沉,在这段经历中,让我学会了第一件事情是——做人、做事需要符合物理、客观的规律,也就是雷军所说的「顺势而为


无业 gap 的时期,并不美好,每天处于没有收入、消耗积蓄的焦虑,所以到了 9 月份,我需要重新开始找工作,自媒体和独立开发被我 pass 掉了,这两者现下并不能带来稳定的收入


又回到了起点,这一次我反而更加自信,充分吸取教训,我需要做好正确的求职策略,搜集各路面试资料,结合自身的实际情况,并且在 AI 的辅助下,写了一份《前端求职大攻略》



把自己求职涉及到的方方面都罗列出来,同时使用 PDCJ 模型,P = Plan(计划),D = Do (执行),C = Check(检查),J = Just(调整),也就是阶段性地计划、施行,再不断地检查、调整,确保自己的面试正确而又高效地进行


就业环境并不会因为你认真做好求职攻略、努力复习就给到丰厚机会,相反,每天投递的数十份简历都石沉大海,一个星期可能都约不到面试机会,这大概就是铜九铁十了吧


求职遇冷,那就好好抓住每一个来之不易面试机会,比如大学舍友的朋友内推了的转转前端岗位,面试前两天,刷完了转转的前端面经,一遍一遍地背前端面试题宝典的八股文,甚至于上厕所,也会拿着小程序刷题



但是,转转还是把我挂了,二面都没进


沮丧是没有用的,迅速复盘转转的整场面试,重听了当时的录音,把自己回答不上的问题找补,犯错的点做具体的纠正,为下一次面试做好准备


不久,意外接到了童心制物 HR 的简历邀请,是一个 Nodejs 的岗位,我拒绝了,如实说目前仅接受前端岗位,HR 却跟我要了简历转发给他们前端部门,没想到还通过了简历筛选,得到了一面的机会


一面发挥的很好,其中问到了一个难题,“如果不用 eval,还有其他方式去执行 js 函数吗”,刚好之前研究过 laf 的源码,知道可以用 vm 模块可以实现。之后又是二面和 HR 面,都顺利通过了,拿到了最终的 offer


童心制物涉及教育方向,这也是我很看重的一个点,大学的时候参加过支教,一直对教育这一块感兴趣,另外,这家公司给的薪资和福利都比较合理,所以……我入职啦



求职告一段落,顺便写了一篇博客作为输出,感兴趣可以查看——《前端开发实用的面试备考分享(内含资料 + 内推)》


这一段求职经历,总体上算是成功的,找到了理想的公司,理想的职位,但人不可能躺在功劳簿上过一辈子,新阶段会有新挑战,需要重新改变,重新努力


入职之后,体验了公司的激光设备,感受到了巨大的创造力:



用 F1 Ultra 雕刻的金属卡片,用 P2S 切割+雕刻的木板:



用 M1 Ultra 和热压机做的工服:



加入了心心念念的篮球社,开启了每周打篮球的固定活动,没想到老板也是篮球迷,现在每周都会一起打,看着他能明显感受身上的年轻、务实,身边的同事也是对他好评,我相信这些称赞不是人情世故


公司没有设立职称体系,转而实行扁平化管理,此举弱化了上下级概念。此外,公司还推行 AMA(Ask Me Anything,即问我任何事)活动,所有员工均可匿名提出任意问题,老板会逐一进行解答。可以看到,公司正在着力打造更为平等、透明、高效的职场环境,这也促使我对自身与企业之间的关系展开深入思考。


思考的结果为:作为员工,其行为与目标应当与公司的发展相契合。基于这一思考,我察觉到自己过往存在一些不良习惯,有时为了维护同事关系,或是顾及上下级的地位差异,对问题视而不见,对待工作打折妥协。


知行合一,慢慢将思考转化为行动,比如与同事协作后,即时给予反馈,对于公司内部平台出现的 bug,立即同步给相应负责人,尽量做到事事有反馈、发挥 owner 精神等等


童心制物很开放,有很多的活动可以参加,比如 Factory Day 工厂日,在周四那天乘着大巴,去到惠州工厂,参观了整条产线,看到了机器从零到一的生产过程



还有 MakeX 机器人挑战赛,这是一个具有重要影响力的国际化机器人赛事和教育平台,今年是第七年了,MakeX 总决赛又回到了深圳举办,立即报名了技术支持,参与了一天的活动现场



场馆设有各个国家的文化摊位,期间还被俄罗斯的大朋友投喂了巧克力零食



看大朋友、小朋友们激烈比赛:



以及让我难过了一天的创客马拉松,这是公司的特色活动,参与的最新的一期比赛,在决赛路演输了,作为队长很自责,忙碌了一周并没有好的结果,促使我进行反思,是带队伍问题?是项目推进问题?是质量问题?还是路演问题?




失败或许不是一件坏事,让我刻骨铭心,反而推着我进步



回头来看,今年最大的里程碑节点是备考雅思失败后的悟“道”,也就是成长性思维,这种认知层面的巨大改变,进而影响了我的工作、生活


我似乎不再害怕去面对我从未遇到的难题,我知道肯定方法、有途径能够去解决它,即使事与愿违,这过程中我也能收获到经验、智慧和勇气


我不再陷入完美主义,先做一个垃圾出来,再慢慢去迭代、优化,不要幻想一下子就能得到 100 分,但先拿到 60 分,再一点点进步,日拱一卒,等待那个增长拐点


我也变得更加正向,“世上只有一种英雄主义,就是在认清生活真相之后依然热爱生活”,坚持开放、乐观的心态,拒绝被悲观、消极所同化


或许我的所谓悟“道”、成长型思维,这些认知只是浅薄的,缺乏更多实践和经历,但是没有关系,做时间的朋友,随着年岁和阅历的增长,这套成长型思维也会随之”成长“


碎碎念的年终总结到此为止,写完之后还是很感慨,今年发生了很多事情,但在当时,只觉得是一个风平浪静的日子,或许此时此刻,也觉得是风平浪静的深夜。弱智吧有一句话,“有人看不到未来,其实是看到了未来”,初看的时候不理解,后来明白了,未来是动态的、不确定的,这就是未来的真面目,以为的看不到,其实恰恰是看到了,所以 2025,未来见


作者:楷鹏Dev
来源:juejin.cn/post/7451924452538548260
收起阅读 »

2024年,30岁前最后一次年度思考

没错!95年,还剩几个月就奔三了。2024年,注定是人生中意义非凡的一年,忐忑、裁员、出书、求职、转正这几个词贯穿了一整年。 忐忑 在上一家公司时,我从面试开始和到入职半年转正后,其实内心对于公司的状况一直保持一种忐忑不安的心情,这种感觉跟我老婆说过几次,我们...
继续阅读 »

没错!95年,还剩几个月就奔三了。2024年,注定是人生中意义非凡的一年,忐忑、裁员、出书、求职、转正这几个词贯穿了一整年。


忐忑


在上一家公司时,我从面试开始和到入职半年转正后,其实内心对于公司的状况一直保持一种忐忑不安的心情,这种感觉跟我老婆说过几次,我们一致认为应当有心理准备。原因在于薪资与公司的组织架构、基础建设、日常工作量安排和人员扩充速度都让人感到迷惑。


公司是在一个包括高层话事人不断更换,高层(副总裁)突然接受停止调查;技术部门仅仅作为辅助,技术氛围低沉,基建缺失,直属leader作用甚微;工作量与人员匹配失常,人多活少,尽管如此年初还在不断扩招中,泡沫感极强,伴随着薪酬发放日漂浮不定,每到月底像是在开盲盒,你永远不知道银彳亍卡何时会有一笔款到账。


裁员


一系列薪酬制度改革和薪酬拖欠不得不怀疑高层战略的正确性,直到四月某一天CTO私聊我,泡沫破裂,裁员尘埃落定。


我被归属于第一批裁员名单中,与CTO交谈中,似乎也流露一丝对高层决策的不满,但没有明说,给我的理由是当前工作任务都很简单,匹配不了我的能力,所以给了我一个名额。


这放在当时听上去有些许意外,但我接受了这种措辞,并不是因为CTO说了几句好听的话,更多是我作为一个技术人的直觉认为这个CTO靠谱。离职过程中对人事提出的补偿计算方式以及分期发放,我都拒绝了,最后经过与人事反复讨论之后拿到了补偿,少不了他的协助,所以内心表示感谢。从现在的视角看来,似乎是他已经意料到公司的发展趋势,以致于后来被裁员的人有很大一部分都没有赔偿。


出书


离职后我在家休息了一个月,期间也为了帮一个粉丝忙,接手了他工作的一部分任务,主要是做游戏业务的动画。期间有被一个后端恶心到,业务不熟悉,接口一直不通就算了,关键还理直气壮说是前端问题;我佩服那个粉丝能够忍气吞声这么久,换做其他人也很难不高血压,为此特意发圈宣泄。
image.png


由于后端提供的接口迟迟不通,需求没有预期上线,为此他们老板还大发雷霆,最后把锅推给了这个前端粉丝,声称把他给炒了。没过一个月,粉丝的这个公司被帽子叔叔查封,业务涉及到了灰产,老板和负责人进去了。员工的工资都没发,但我的报酬是因为签了合约,在deadline之前要求他们打款,对我没有影响,这是苦了这个粉丝。


在此之后我便全职写书,《NestJS全栈开发解析:快速上手与实践》 这本书临近结尾,我一鼓作气完成了并在5.1号劳动节那天交稿;写书的想法也有一部分是来源于CTO的启发,后面图书审阅也是找了CTO帮忙,熬夜帮我看完并给了这个评语,为此我很感谢他。


经过几个月的审批和改稿,图书在9月份正式发布了各大平台,这是一件值得高兴的事情。


image.png
而对于前司的后续,据说后面还搬到一个CBD进行办公,但当时员工已经欠薪几个月,以至于到年底,公司被迫全员原地解散,很遗憾这不是一个好结果。


求职


交稿完成后,花了一个月左右时间求职,拿到了3个offer,最后选择了去深圳的美图,这是凭借NestJS的图书写作获得的一个岗位。之后由于组织架构变化,我在转正前夕面临选择继续从事Node全栈还是Go语言开发,考虑一番后我选择了后者,顺利转到了后端架构组,负责go语言开发,这对我来说又是一个新的尝试和挑战,我选择了这种变化,与框架和语言无关,只不过是践行我的人生哲学:【不断变化】,让自己处于一种长期乐观、短期痛苦、当下快乐的舒适区边缘中。


觉醒


关于成长,过去我一直不喜欢看历史,或许归根于上学时代对于历史学科的厌倦,没看过基本历史文献。2024年底,我看了教员的《毛选》、《实践论》、《矛盾论》、《寻乌调查》,第一种感受是成功绝不是偶然,环环相扣的逻辑能力令人惊叹。我想这些书籍回答了我一直以来的问题:



如何成为一个独立、深度思考的人?



我们人生中做了一个坏的决定,在股市中选择了不争气的股票,最坏的结果无非是让自己从头再来。但革命不同,选择错了就有可能让整个民族处于被毁灭的境地中,每一步都步履蹒跚,这该有怎样的智慧与思维?


第二种感受是遗憾没有早点开悟,在临近30岁时才开始阅读这些书籍,当然也很庆幸没有太晚,一切都来得及!


特别的是,《寻乌调查》报告里面的细节,应该是我人生中读过的一本最详细的一本书籍,里面还记载了寻乌与我老家(兴宁)相关的历史宜了,没有一句多余的,都是干货。第一次感受原来伟人离我这么近。


image.png


教员做了这个调查报告之后,便留下一句千古格言:没有调查,就没有发言权!反观自身,何尝不是应该这样呢?


关于家庭,今年整个过程中家里的大大小小的事基本上都是我老婆操办,为我们的小家默默付出了很多,加上我去了深圳之后,我的衣食住大部分也是她来打理,一个人照顾小孩,现在甜筒一岁半了,如我们所愿健康成长,这隶属她的功劳。


一个家庭要想变好,靠一个人努力不行,需要“拉拢”有能力的人一起,话事人脑子要清醒,能够明辨是非,唯唯诺诺绝对是会出问题的。


一个家族要想变好,靠一两个人不行,得靠一两个家庭真正向好,大家庭才会有希望。


最后,没有Flag,年度总结中对未来进行遐想没有意义,沉浸于自己完成所有Todo List的那种兴奋是虚构的,而实践中那种痛苦、无助才是我们最真实的感受,人不能总活在无限遐想的递归当中


我看过那些在新年Flag列举诸多愿望,买了一堆书籍想要读完的,来年能真正落地完成的少之又少,毕竟我亦如此。


2025年,爱自己,爱家人,步步为营,不负将来!祝所有支持我的粉丝朋友们,一切如意,事业感情双丰收~


作者:元兮
来源:juejin.cn/post/7455282891535302708
收起阅读 »

博弈论(一):身在大厂,平衡工作和家庭太难了

引言 什么是博弈论(Game Theory)?百度百科的介绍如下 博弈论,又称为对策论(Game Theory)、赛局理论等,既是现代数学的一个新分支,也是运筹学的一个重要学科。 博弈论主要研究公式化了的激励结构间的相互作用,是研究具有斗争或竞争性质现象的数...
继续阅读 »

引言


什么是博弈论(Game Theory)?百度百科的介绍如下



博弈论,又称为对策论(Game Theory)、赛局理论等,既是现代数学的一个新分支,也是运筹学的一个重要学科。


博弈论主要研究公式化了的激励结构间的相互作用,是研究具有斗争或竞争性质现象的数学理论和方法。博弈论考虑游戏中的个体的预测行为和实际行为,并研究它们的优化策略。生物学家使用博弈理论来理解和预测进化论的某些结果。


博弈论已经成为经济学的标准分析工具之一。在金融学、证券学、生物学、经济学、国际关系、计算机科学、政治学、军事战略和其他很多学科都有广泛的应用。



博弈论在生活中的影响无处不在,比如许多朋友会面临一种选择选择,两家公司给你发了offer,一家公司薪资高,职位高,但可能需要频繁加班,压力很大。另一家公司薪资比你现在低一些,但是可以保证你准时下班,让你有充足的业余时间。对于单身的人来说这个并不难选择,但是当你结婚生子,这个问题就会瞬间变得复杂。


还有一个现象,为什么当团队内有一个人下班晚,整个团队的下班平均时间就都会往后延。


学习博弈论,只为了一件事情:拥有识别博弈格局的眼光,拥有改变规则的意识。简单来说,先理解长期存在的现象,并能够去改变不好的局面。


看完这篇文章,你或许就会拥有一个全新的视角去看这个世界。


介绍博弈论,我们先从三个基本概念开始,分别是帕累托最优,囚徒困境和纳什均衡。


帕累托最优


每一个成家、有孩子的人,再找工作时都会考虑如何平衡工作、收入、家庭三者之间的关系,说白了就是钱多事少离家近。


你现在有一份不错的工作,有一份稳定的收入,到了下班时间,你回家陪伴家人,辅导孩子写作业,顺便还能做做家务。公司、家人对你很满意,有房有车,收入足以满足日常花销,甚至有点小积蓄。


其实外面有其他公司给你抛来了橄榄枝,有的公司承诺如果你过去,会给你升值加薪。当然也有别的机会,你工作可能更清闲,但你的收入也会下降。


你很难做出抉择,你不是一个个体,你还需要考虑别人的选择。因为你一旦选择更高收入,就意味着要做更多的工作,没法按时下班,家人会对你有意见。新工作压力可能很大,你的状态也会变差,你不但没法照顾家人,可能家人还要额外提供给你情绪价值,家人一定会不满意。


此时,你在工作、收入、家庭取得了平衡,你无法在不影响收入和家人满意度的情况下去换另一份工作,此时的局面就叫做“帕累托最优”。


我们都希望工作和家庭最理想的状态是帕累托最优的,可我们都知道,生活中似乎很难达到这个状态,帕累托最优这个状态很理想化,因为它是不稳定的。


博弈论要求我们需要考虑竞争对手怎么做,虽然我不想把工作称之为竞争对手,但是在这个三角关系中,这里的竞争对手就是你的工作。


工作中公司一定要求你尽职尽责的完成本质工作,你要能够承担一定的责任,最好你要有一点创新,能够给公司带来一定改变,带来额外的价值。


一直以来你自己负责一个项目,这时候你的工作由你自己安排,要做的事情有很多,但你有没有三头六臂,那你只能一件一件来。当天既然没法做完所有工作,那到点下班就好。


可你的项目越来越有前景,公司决定增加人手,公司招进来了另一位同事,我们叫他小齐。现在你俩需要一起负责这个项目,你们既是合作关系,又是竞争关系。


那工作还是这么多,却有两个人来干了。如果你按点下班,可同事还想“承担”,他多做一点,你就少做一点,时间长了对你可不是一个好消息,你不得不选择加班。


compressed_pexels-cottonbro-6944006.jpg


这也就解释了为什么有时候一个团队只要有一个人加班,大家普遍的下边时间都会变晚,也称之为内卷。


这时候你想了一个办法,你请同事吃了一顿饭,你说你还单身,你得丰富一下业余生活。我认识一个单身的女同事,听说你俩爱好挺像,我把她微信推给你,以后你们下班可以一起约着出去玩。


后来你们都不加班了,你们依然是平等竞争,而且你又可以按时回家陪娃了,这就叫“帕累托改进”。


压倒性策略


或许你听过囚徒困境的故事,囚徒困境的故事最适合解释这个概念,但你和小齐的故事还在继续。


(注:下面的例子纯属虚构,如有雷同,纯属巧合)


你和小齐接手了全新的项目,有大量的代码开发工作,你俩的技术水平相当。可之前你给他介绍的单身女同事,后来找了男朋友,可惜那个人不是他。他感觉被套路了,给你说在你没有给他介绍下一个对象之前,他暂时决定和你势不两立。


可工作还得继续,你们都可以选择写出高质量的代码,需要花费更多的精力,但很明显你的口碑会变好。也可以得过且过,写出质量一般的代码,工作量明显变少,但项目质量可能一般。


根据两人的选择,存在几种情况



  • 两人都贡献高质量代码,项目质量得到广泛认可和领导称赞,声誉增加了

  • 如果一人费心费力提供了高质量代码,而另一个人敷衍了事,代码不规范、质量差。那么项目依然会正常上线,写低质量代码的人可以说是被大佬带飞(+7),而高质量代码因为加班、熬夜,所获的收益变少了(+2)

  • 如果两人都敷衍了事,上线之后问题频发,虽然工作完成了,可产品运营会不停的和你领导吐槽,领导对你们的印象大打折扣(+3)


注意:我们这个例子不考虑这个工作对于后续年终奖或职业生涯发展如何。就只针对这个工作,我们来分析一下你和小齐的博弈策略。首先我们把不同的策略和结果画在下面这个矩阵图里。多说一句,这种画法是美国经济学家托马斯·谢林发明的。


小齐贡献高质量代码小齐贡献低质量代码
你贡献高质量代码你:+5,小齐+5你:+2,小齐+7
你贡献低质量代码你:+7,小齐+2你:+3,小齐+3

其实你明显看可以看出,最好的结果就是两个人都贡献高质量的代码,然后项目稳定,还能收获良好的口碑。


但是,博弈论要求我们每次做判断都要考虑对方-----并不是说怎么样对对方好,而是对方会如何选择,然后你根据对方的选择再考虑怎么做。


我们具体看看你的收益分析:



  • 如果小齐开源高质量代码:你选择开源高质量代码,收益为 +5。你选择写低质量代码,收益为 +7。 (低质量代码收益更高)

  • 如果小齐开源低质量代码: 你选择开源高质量代码,收益为 +2。你选择开源低质量代码,收益为 +3。 (低质量代码收益更高)


你发现,无论小齐怎么做,你选择写一些低质量的代码,你的收益都会更高!于是你来说,选择写份低质量的代码,就是一个压倒性策略


可反过来对小齐来说呢,这就是一个被压倒策略!但博弈论的前提是大家都是理性人,小齐也聪明的很,于是他也意识到选择写低质量代码,是一个压倒性策略。


对理性人来说,在博弈中一定要选择压倒性策略,任何情况下都不要选择被压倒性策略。


你俩同时这样选择,这就引出接下来的一个最重要的概念,纳什均衡。


纳什均衡


上面说到你俩同时放松了对自己的要求,写的代码缺乏设计,代码不健壮,上线之后问题频发,领导对你俩很不满。


这个结果可不是帕累托最优,但这个结果是稳定的,不管我们是否喜欢这个局面,但我们认可这个局面了。


线上一直报警,产品运营一直来找我们排查问题,这些都惹人心烦。我们或许都想把项目做好,但在这个组合里,没有一个人愿意单方面改变自己的策略。


因为无论对谁来说,此时选择去写高质量代码,都会让自己的利益受损,谁不想更轻松一点呢?


这种没有任何一方愿意单方面改变策略的局面,就是纳什均衡


纳什均衡的概念由约翰·纳什提出,他是著名数学家、经济学家,还是《美丽心灵》男主角原型,他与另外两位数学家在非合作博弈的均衡分析理论方面做出了开创性的贡献,对博弈论和经济学产生了重大影响,而获得1994年诺贝尔经济学奖。


FE826890-FA8F-4813-98D6-5695D394BFD7.png


文章开头的对于找工作和家庭的例子就是一个纳什均衡,要记住纳什均衡不是最优的局面,如果你观察到身边的人在一家公司干了5年甚至10年以上,他的薪资或许会落后于市场平均水平,但对他来说,这份工作对于工作、生活、收入来说,大概就是一个纳什均衡。当然有的工作也可能不让你准时下班,甚至可能让你没有业余时间,就像一个在大厂996,忙到没有时间顾家和看娃的人来说,这也是一个纳什均衡。


如果你观察到社会上的一个现场长期稳定的存在,它对于所有参与方来说就是一个纳什均衡。纳什均衡告诉我们评价一个事情不能看它是不是对整体最好,它必须要让所有参与者都不愿单方面改变才行。


说在最后


公司领导发现项目问题不断,悄悄从HR那里调出了你和小齐的打卡记录,赫然发现你们天天5:30准时打卡,项目问题这么多,你俩准时下班,难怪运营天天说问题解决不及时,他决定宣布,在这个项目结束之前,项目组实行996工作制。


本来还想平衡好工作和家庭,这下可好了,不但日常加班,还损失了周六的时间。


那你说,这该怎么办呢?欢迎你在评论区说出你的看法,也希望你点赞、评论、收藏,让我知道对你有所收获,这对我来说很重要。也欢迎你加我的wx:Ldhrlhy10,一起交流~


本篇文章是第65篇原创文章,2024目标进度65/100,欢迎有趣的你,关注我。


作者:东东拿铁
来源:juejin.cn/post/7449172888689836047
收起阅读 »

前端ssr项目被打崩后,连夜做限流!

web
token-bucket-limiter-redis 是一个令牌桶算法 + redis 的高效限流器,用于Node服务接口限流。 当然作为一个前端你可能很少接触Node接口开发,用的接口应该都是后端同学提供的,他们有自己的限流策略,但是你一定使用过SSR框架来...
继续阅读 »

token-bucket-limiter-redis 是一个令牌桶算法 + redis 的高效限流器,用于Node服务接口限流。


当然作为一个前端你可能很少接触Node接口开发,用的接口应该都是后端同学提供的,他们有自己的限流策略,但是你一定使用过SSR框架来开发服务端渲染项目,那么此时你的项目就只能靠我们自己来做限流了,否则遇到突发流量时,你的项目可能很容易崩溃。



  • 使用令牌桶算法实现

  • 支持基于内存和基于 redis 存储的两种选择,满足分布式限流需要

  • 高性能,令牌生产的方式为每次请求进来时一次性生产上一次请求到本次请求这一段时间内的令牌,而不是定时器生成令牌

  • 快速,使用 lua 脚本与redis通讯,lua 支持将多个请求通过脚本的形式一次发送到服务器,减少通讯,并且脚本支持缓存,多客户端可以复用

  • 安全,lua 脚本保证redis命令执行的原子性

  • 内存效率高,键过期后自动删除,不占用过多内存

  • 提供多种极端场景下的降级和容错措施



其他限流方法的对比,大家可以自行搜索,这里就不赘述了,令牌桶算法是更适合大部分场景的限流方案。


令牌桶算法:按照一定的速率生产令牌并放入令牌桶中,最大容量为桶的容量,如果桶中令牌已满,则丢弃令牌,请求过来时先到桶中拿令牌,拿到令牌则放行通过,否则拒绝请求。这种算法能够把请求均匀的分配在时间区间内,又能接受服务可承受范围内的突发请求。所以令牌桶算法在业内较为常用。




该项目github地址:token-bucket-limiter-redis



安装


npm i --save token-bucket-limiter-redis

引入


import { RateLimiterTokenBucket, RateLimiterTokenBucketRedis } from 'token-bucket-limiter-redis';

使用


限流方案我们分为无状态限流器和有状态限流器两种:


有状态的限流器(区分key的限流器):这种限流器会根据某种标识(如IP地址、用户ID、url等)来进行区分,并对每个标识进行单独的限流。可以更精细地控制每个用户或者每个IP的访问频率。


无状态的限流器(不区分key的限流器):这种限流器不会区分请求的来源,只是简单地对所有请求进行统一的限制。


基于内存的无状态限流器


const globalRateLimiter = new RateLimiterTokenBucket({
tokenPerSecond: 100,
capacity: 1000,
});

const globalTokens = globalRateLimiter.getToken();

if(globalTokens > 0){
// pass
}


基于内存的有状态限流器,自定义key


const globalRateLimiter = new RateLimiterTokenBucket({
tokenPerSecond: 5,
capacity: 5,
keyPrefix: 'test', // 指定限流器所属项目或模块
});

const key = ip + uid; // 标识用户信息的key

const globalTokens = globalRateLimiter.getToken(key);

if(globalTokens > 0){
// pass
}


这里附上 node 端获取ip的方法



function getClientIp(req) {
// 获取 X-Real-IP 头部字段
const xRealIP = req.headers['x-real-ip'];

// 优先使用 X-Real-IP 头部字段
if (xRealIP) {
return xRealIP;
}

// 获取 X-Forwarded-For 头部字段,通常包含一个或多个IP地址,最左侧的是最初的客户端IP
const xForwardedFor = req.headers['x-forwarded-for'];

// 如果 X-Real-IP 不存在,但 X-Forwarded-For 存在,则使用最左侧的IP地址
if (xForwardedFor) {
const ipList = xForwardedFor.split(',');
return ipList[0].trim();
}

// 获取连接的远程IP地址
const remoteAddress = req.connection?.remoteAddress;
// 如果都不存在,使用连接的远程IP地址
if (remoteAddress) {
return remoteAddress;
}

return '';
}

基于内存的有状态限流器,使用ip作为默认key


const globalRateLimiter = new RateLimiterTokenBucket({
tokenPerSecond: 5,
capacity: 5,
keyPrefix: 'test', // 指定限流器所属项目或模块
});

// 使用 ip 作为key,无需传入,自动获取ip
const globalTokens = globalRateLimiter.getTokenUseIp(req);

// 使用 ip 加上自定义的其他key,如传入则组合在ip后 ip+uid
const globalTokens = globalRateLimiter.getTokenUseIp(req, uid);

if(globalTokens > 0){
// pass
}



注意,单纯使用ip作为限流key可能会有问题,有以下几种可能过个机器的外网ip相同的情况:



  • 使用共享的公共 IP 地址: 在一些特殊的网络环境下,多个设备可能共享同一个公共 IP 地址,如咖啡馆、图书馆等提供 Wi-Fi 服务的地方。在这种情况下,所有连接到同一网络的设备都会共享相同的公共 IP。

  • 使用代理服务器: 如果多个机器通过相同的代理服务器访问互联网,它们可能会在外网上表现为相同的 IP 地址,因为代理服务器向互联网发起请求,而不是直接来自每个终端设备。

  • 使用 NAT(网络地址转换): 在家庭或企业网络中,使用了 NAT 技术的路由器可能会导致多个内部设备共享同一个外网 IP 地址,同一公司下的内网设备公网ip可能是同一个。



综上,如果你需要考虑以上集中情况的话,你需要结合其他可以标识用户身份的key,如uid,浏览器指纹等:


// 使用 ip 加上自定义的其他key,如传入则组合在ip后 ip+uid
const globalTokens = globalRateLimiter.getTokenUseIp(req, uid);

附上浏览器指纹获取方法:


function generateFingerprint() {
try {
// 收集一些浏览器属性
const userAgent = navigator.userAgent || '';
const screenResolution = `${window.screen.width}x${window.screen.height}`;
const language = navigator.language || '';
const platform = navigator.platform || '';

// 将这些属性组合成一个简单的指纹
const fingerprint = userAgent + screenResolution + language + platform;

// 返回指纹
return fingerprint;
} catch (error) {
return '';
}
}

在 express 中使用


const express = require('express');
const app = express();

const globalRateLimiter = new RateLimiterTokenBucket({
tokenPerSecond: 5,
capacity: 5,
keyPrefix: 'test', // 指定限流器所属项目或模块
});

// 全局中间件
app.use((req, res, next) => {
console.log('Express global middleware');
// 使用 ip 作为key,无需传入,自动获取ip
const tokens = globalRateLimiter.getTokenUseIp(req);

if(tokens > 0){
next();
}else {
res.status(429).send({ message: 'Too Many Requests' })
}
});

app.listen(3000, () => {
console.log('Express app listening on port 3000');
});

在 koa 中使用


const Koa = require('koa');
const app = new Koa();

const globalRateLimiter = new RateLimiterTokenBucket({
tokenPerSecond: 5,
capacity: 5,
keyPrefix: 'test',
});

// 全局中间件
app.use(async (ctx, next) => {
console.log('Koa global middleware');
// 使用 ip 作为 key,无需传入,自动获取 ip
const tokens = globalRateLimiter.getTokenUseIp(ctx.req);

if (tokens > 0) {
await next();
} else {
ctx.status = 429;
ctx.body = { message: 'Too Many Requests' };
}
});

app.listen(3000, () => {
console.log('Koa app listening on port 3000');
});


在 fastify 中使用


const fastify = require('fastify')();

const globalRateLimiter = new RateLimiterTokenBucket({
tokenPerSecond: 5,
capacity: 5,
keyPrefix: 'test',
});

// 全局中间件
fastify.addHook('onRequest', (request, reply, done) => {
console.log('Fastify global middleware');
// 使用 ip 作为 key,无需传入,自动获取 ip
const tokens = globalRateLimiter.getTokenUseIp(request);

if (tokens > 0) {
done();
} else {
reply.status(429).send({ message: 'Too Many Requests' });
}
});

fastify.listen(3000, (err) => {
if (err) throw err;
console.log('Fastify app listening on port 3000');
});


基于redis的无状态限流器,传入redis客户端


支持分布式限流,外部传入redis客户端 (由ioredis包创建)


import Redis from 'ioredis';

const redis = new Redis({});

const globalRateLimiter = new RateLimiterTokenBucketRedis({
tokenPerSecond: 100,
capacity: 1000,
keyPrefix: 'test', // 指定限流器所属项目或模块
redisClient: redis,
});

const key = 'myproject'; // 使用全局唯一key (当key省略时,默认为RateLimiterTokenBucketGlobalKey)

const globalTokens = globalRateLimiter.getToken(key);

if(globalTokens > 0){
// pass
}


基于redis的有状态限流器,传入redis客户端


支持分布式限流,外部传入redis客户端 (ioredis)


import Redis from 'ioredis';

const redis = new Redis({});

const globalRateLimiter = new RateLimiterTokenBucketRedis({
tokenPerSecond: 5,
capacity: 5,
keyPrefix: 'test', // 指定限流器所属项目或模块
redisClient: redis,
});

const key = ip + uid; // 标识用户信息的key
const globalTokens = globalRateLimiter.getToken(key);

// 使用 ip 作为key
const globalTokens = globalRateLimiter.getTokenUseIp(req);

// 使用 ip + 自定义key
const globalTokens = globalRateLimiter.getTokenUseIp(req, key);

if(globalTokens > 0){
// pass
}


基于redis的有状态限流器,使用内置redis


外部仅需传入redis配置(ioredis)


const redisOptions = {
port: 6379, // Redis 端口
host: 'localhost', // Redis 主机名
password: 'password' // 如果有的话,你的 Redis 密码
db: 0,
};

const globalRateLimiter = new RateLimiterTokenBucketRedis({
tokenPerSecond: 5,
capacity: 5,
keyPrefix: 'test', // 指定限流器所属项目或模块
redisOptions: redis,
});

const key = ip + uid; // 标识用户信息的key

const globalTokens = globalRateLimiter.getToken(key);

if(globalTokens > 0){
// pass
}


添加内存阻塞策略


内存阻塞策略可以保护redis服务器,抵御DDoS攻击


const redisOptions = {
port: 6379, // Redis 端口
host: 'localhost', // Redis 主机名
password: 'password' // 如果有的话,你的 Redis 密码
db: 0,
};

const globalRateLimiter = new RateLimiterTokenBucketRedis({
tokenPerSecond: 5,
capacity: 5,
keyPrefix: 'test', // 指定限流器所属项目或模块
redisOptions: redis,

// 内存阻塞策略(只计算当前服务器或实例的请求数,非分布式)
inMemoryBlockOnConsumed: 50, // 如果某个key在一分钟内消耗的令牌数量超过 50,将在内存中阻塞该key的请求,不会发起redis,防止DDoS攻击
inMemoryBlockDuration: 10, // 阻塞持续时间s
});

const key = ip + uid; // 标识用户信息的key

const globalTokens = globalRateLimiter.getToken(key);

if(globalTokens > 0){
// pass
}


getToken 方法支持第二个参数,传入判断阻塞的标识键,通常是ip或用户id,因为我们要阻塞的是某个具体的用户或机器,不传的话默认使用第一个参数,即令牌标识键。


当你使用无状态限流器,或是有状态限流器的键无法标识某个具体用户时可能需要填写该参数:


const key = 'myproject'; // 无状态限流器
const key = 'url'; // 有状态限流器,但是只限制某个路由

const blockKey = 'ip'; // 阻塞标识键须使用ip或用户id

const globalTokens = globalRateLimiter.getToken(key, blockKey);

// 使用 ip + 自定义key
const globalTokens = globalRateLimiter.getTokenUseIp(req, key, blockKey);

if(globalTokens > 0){
// pass
}


内存阻塞策略优先于redis限流器以及redis保险策略,即使redis不可用时内存阻塞策略依旧生效。


添加保险策略,配置当redis服务错误时是否自动使用内存限制器


const redisOptions = {
port: 6379, // Redis 端口
host: 'localhost', // Redis 主机名
password: 'password' // 如果有的话,你的 Redis 密码
db: 0,
};

const globalRateLimiter = new RateLimiterTokenBucketRedis({
tokenPerSecond: 5,
capacity: 5,
keyPrefix: 'test', // 指定限流器所属项目或模块
redisOptions: redis,

// 内存阻塞策略
inMemoryBlockOnConsumed: 50, // 如果某个key在一分钟内消耗的令牌数量超过 50,将在内存中阻塞该key的请求,不会发起redis,防止DDoS攻击
inMemoryBlockDuration: 10, // 阻塞持续时间s

// 保险策略,使用内存限流器
insuranceLimiter: true,
insuranceLimiterTokenPerSecond: 3, // 如果未填写将取tokenPerSecond的值
insuranceLimiterCapacity: 3, // 如果未填写将取capacity的值
});

const key = ip + uid; // 标识用户信息的key

const globalTokens = globalRateLimiter.getToken(key);

if(globalTokens > 0){
// pass
}


开启保险策略后,支持传入保险限制器的每秒令牌数和令牌桶容量,如果不传,将取redis限流器的值。


当你的服务是集群部署时,例如使用 pm2 的集群模式时,会用到这些选项,因为使用redis时令牌是共享的,而集群模式下每个服务是一个实例,每个实例有自己的内存空间,所以你要适当地考虑使用内存限流器时每个实例的限流速率。


注意事项



  1. 基于内存的限流器更适用于单机限流的场景,集群或分布式部署时,如果你不能计算出每一个实例的合适限流配置的话推荐使用基于redis的限流器。


FAQ


不使用定时器生成令牌有什么好处?


时间精度:定时器的精度可能会受到系统调度和网络延迟的影响,这可能导致令牌的生成速率无法精确控制。


资源消耗:如果令牌桶的数量非常多,那么需要维护的定时器也会非常多,这可能会消耗大量的系统资源。


时间同步:由于精度问题,如果系统中存在多个令牌桶,且每个令牌桶都使用自己的定时器,那么这些定时器之间可能并不同步。


冷启动问题:如果使用定时器生成令牌,那么在服务刚启动时,令牌桶可能会是空的,这可能导致在服务启动初期无法处理请求。


除了ip还有哪些可以标识具体用户的key



  • 浏览器指纹

  • 用户id

  • 用户名

  • 邮箱

  • 手机号

  • 其他可以标识用户身份的key


// 生成浏览器指纹
export function generateFingerprint() {
try {
// 收集一些浏览器属性
const userAgent = navigator.userAgent || '';
const screenResolution = `${window.screen.width}x${window.screen.height}`;
const language = navigator.language || '';
const platform = navigator.platform || '';

// 将这些属性组合成一个简单的指纹
const fingerprint = userAgent + screenResolution + language + platform;

// 返回指纹
return fingerprint;
} catch (error) {
return '';
}
}

作者:Pursue_LLL
来源:juejin.cn/post/7454095190379888666
收起阅读 »

离职后,前领导突然找你回去帮忙写代码解决问题,该怎么办?

题目中的这个问题,我相信有遇到过这种情况的同学的第一反应是:"诶,是要白嫖我还是说解决完问题给钱呀",且听我接下来慢慢分析。 首先要说的是,这种没头没尾的突发情况,一般大部分人都是很难遇到的。 原因也很简单,老板大部分也都是打过工,当过员工的,也是一路从职场老...
继续阅读 »

题目中的这个问题,我相信有遇到过这种情况的同学的第一反应是:"诶,是要白嫖我还是说解决完问题给钱呀",且听我接下来慢慢分析。


首先要说的是,这种没头没尾的突发情况,一般大部分人都是很难遇到的。


原因也很简单,老板大部分也都是打过工,当过员工的,也是一路从职场老油子混成的老板,很多人情世故,员工的小心思,老板其实都门儿清,甚至比很多员工都更熟。


如果公司里的一些工作是交接时不太能完全搞定的,可能还需要离职的员工继续帮忙的,一般在员工离职前的时候,就各种协商好了。


而像这种“突发情况”,大部分老板在联系离职的员工回去帮忙前,一般也都会把员工会想到的那些事儿,早就想了很多遍了,基本上相关问题都会在联系员工的时候说明白。


比如很多人都提到的报酬问题,这个基本上都是作为老板不可能回避,也不可能不知道的。


如果老板在联系员工的时候什么都提了,就是没聊这个。


那肯定是老板不想给报酬,还在做着让员工回来白干活的美梦。


不可否认,现实中确实有挺多这样的老板


所以,我的经验就是,如果老板在主动联系离职员工回来帮忙的时候,都没提报酬的事儿,那基本上就是不打算给,基本上你问了也是白问。


当然,大部分人都会遇到的情况是,本来跟老板领导关系也不错,老板领导也知道这一点,所以才会跟已经离职的员工开这个口。


这种时候,大部分人看在老板领导人还不错的份儿上,还是愿意回去帮忙的。


至于会和现在的工作造成的一些冲突,比如时间上走不开,现在住得离公司远,这些也都是可以直接明说的事儿,说了后,要么老板可以帮你解决,要么老板心里会知道你回来帮这次忙的成本有多高。


我以前工作过的公司,别说离职走的同事了,有一次是碰到了一个实习生经手的项目,上面很多东西没按照公司规范写,后来看到这些资料的员工整不明白是怎么回事。


但是,部门领导在知道了这件事后,在知道了这个实习生的同学就在本部门工作的情况下,并没有说让这位同学去搞定这个问题。


而是让这位同学联系好那位实习生后,领导亲自开车带着这位同学和要用到这个资料的人,专门在下班时间守在这位实习生的工作单位门口,接着他去一家还不错的餐厅,边吃饭边解决了这个问题。


至于很多人提的,跟老板没啥交情,甚至关系还不怎么好的,那还纠结什么,直接不理或拒绝就行了,但也没必要把话说得太绝。


毕竟,如果老板真的意识到你这边不好搞,同时也只有找你来帮忙是最划算的选择后,一般都会开出更高的加码,如果加码合适,你还是可以考虑一下的。


但是一定要就是论事,划定要解决问题的范围,要不然赖上你了有问题就找你可还行,同时也要注意不要留下太多痕迹。比如你回来帮忙,是不是属于违规行为,再比如请你回来帮忙的时候,装作无意间打听你现在公司的一些事儿,这个事儿很可能属于工作机密,毕竟大家都是同行,这些一定要注意。


综上我觉得,解决这个问题的公式是:上来先拖字诀、加各种不容易各种不行,这种能挡掉99%的需求,毕竟这么大个公司离了我这个小兵还不能转了咋地;实在不行了在谈什么样的条件你才能去帮忙解决问题,而且记住是单次解决问题的条件。


---程序员职场闲聊公众号:网管叨bi叨


作者:kevinyan
来源:juejin.cn/post/7322344486159826996
收起阅读 »

用java做物品识别和姿态识别

前言 之前搞得语音识别突然发现浏览器就有接口可以直接用,而且识别又快又准,参考:使用 JavaScript 的 SpeechRecognition API 实现语音识别_speechrecognition js-CSDN博客 进入正题 这个功能首先要感谢一下作...
继续阅读 »

前言


之前搞得语音识别突然发现浏览器就有接口可以直接用,而且识别又快又准,参考:使用 JavaScript 的 SpeechRecognition API 实现语音识别_speechrecognition js-CSDN博客


进入正题


这个功能首先要感谢一下作者常康,仓库地址(gitee.com/agriculture… 这个项目很早之前就关注了,最近这段时间正好要用才真正实践了一下,只是初步测试了一下,在性能方面还需要进一步测试,本人电脑就很拉识别就很卡。


先看效果


20240912_090041 00_00_00-00_00_30.gif


20240912_091337 00_00_00-00_00_08 00_00_00-00_00_30.gif


改动


主要对姿态识别做了一些小改动,将原图片识别改成视频视频识别,如果要调用摄像头将video.open(0);的代码注释放开即可


package cn.ck;

import ai.onnxruntime.OnnxTensor;
import ai.onnxruntime.OrtEnvironment;
import ai.onnxruntime.OrtException;
import ai.onnxruntime.OrtSession;
import cn.ck.config.PEConfig;
import cn.ck.domain.KeyPoint;
import cn.ck.domain.PEResult;
import cn.ck.utils.Letterbox;
import nu.pattern.OpenCV;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.highgui.HighGui;
import org.opencv.imgproc.Imgproc;
import org.opencv.videoio.VideoCapture;
import org.opencv.videoio.Videoio;

import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/*
* 姿态识别,可以识别动作等等.,比如跳绳技术
*/

public class PoseEstimation {

static {
// 加载opencv动态库
//System.load(ClassLoader.getSystemResource("lib/opencv_java470-无用.dll").getPath());
OpenCV.loadLocally();
}

public static void main(String[] args) throws OrtException {

String model_path = "src\main\resources\model\yolov7-w6-pose-nms.onnx";
// 加载ONNX模型
OrtEnvironment environment = OrtEnvironment.getEnvironment();
OrtSession.SessionOptions sessionOptions = new OrtSession.SessionOptions();
OrtSession session = environment.createSession(model_path, sessionOptions);
// 输出基本信息
session.getInputInfo().keySet().forEach(x -> {
try {
System.out.println("input name = " + x);
System.out.println(session.getInputInfo().get(x).getInfo().toString());
} catch (OrtException e) {
throw new RuntimeException(e);
}
});

VideoCapture video = new VideoCapture();

// video.open(0); //获取电脑上第0个摄像头

//可以把识别后的视频在通过rtmp转发到其他流媒体服务器,就可以远程预览视频后视频,需要使用ffmpeg将连续图片合成flv 等等,很简单。
if (!video.isOpened()) {
System.err.println("打开视频流失败,未检测到监控,请先用vlc软件测试链接是否可以播放!,下面试用默认测试视频进行预览效果!");
video.open("video/test2.mp4");
}
// 跳帧检测,一般设置为3,毫秒内视频画面变化是不大的,快了无意义,反而浪费性能
int detect_skip = 4;

// 跳帧计数
int detect_skip_index = 1;

// 最新一帧也就是上一帧推理结果
float[][] outputData = null;

//当前最新一帧。上一帧也可以暂存一下
Mat img = new Mat();


// 在这里先定义下线的粗细、关键的半径(按比例设置大小粗细比较好一些)
int minDwDh = Math.min((int)video.get(Videoio.CAP_PROP_FRAME_WIDTH), (int)video.get(Videoio.CAP_PROP_FRAME_HEIGHT));
int thickness = minDwDh / PEConfig.lineThicknessRatio;
int radius = minDwDh / PEConfig.dotRadiusRatio;
// 转换颜色空间
Mat image = new Mat();

// 图像预处理
Letterbox letterbox = new Letterbox();
letterbox.setNewShape(new Size(960, 960));
letterbox.setStride(64);


// 使用多线程和GPU可以提升帧率,线上项目必须多线程!!!,一个线程拉流,将图像存到[定长]队列或数组或者集合,一个线程模型推理,中间通过变量或者队列交换数据,代码示例仅仅使用单线程
while (video.read(img)) {
if ((detect_skip_index % detect_skip == 0) || outputData == null) {
Imgproc.cvtColor(img, image, Imgproc.COLOR_BGR2RGB);
image = letterbox.letterbox(image);
int rows = letterbox.getHeight();
int cols = letterbox.getWidth();
int channels = image.channels();
// 将图像转换为模型输入格式
float[] pixels = new float[channels * rows * cols];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
double[] pixel = image.get(j, i);
for (int k = 0; k < channels; k++) {
pixels[rows * cols * k + j * cols + i] = (float) pixel[k] / 255.0f;
}
}
}
detect_skip_index = 1;
OnnxTensor tensor = OnnxTensor.createTensor(environment, FloatBuffer.wrap(pixels), new long[]{1L, (long) channels, (long) rows, (long) cols});
OrtSession.Result output = session.run(Collections.singletonMap(session.getInputInfo().keySet().iterator().next(), tensor));

// 处理输出结果并绘制
outputData = ((float[][]) output.get(0).getValue());
}else{
detect_skip_index = detect_skip_index + 1;
}
double ratio = letterbox.getRatio();
double dw =letterbox.getDw();
double dh = letterbox.getDh();
List<PEResult> peResults = new ArrayList<>();
for (float[] outputDatum : outputData) {
PEResult result = new PEResult(outputDatum);
if (result.getScore() > PEConfig.personScoreThreshold) {
peResults.add(result);
}
}

// 对结果进行非极大值抑制
peResults = nms(peResults, PEConfig.IoUThreshold);

for (PEResult peResult: peResults) {
System.out.println(peResult);
// 画框
Point topLeft = new Point((peResult.getX0()-dw)/ratio, (peResult.getY0()-dh)/ratio);
Point bottomRight = new Point((peResult.getX1()-dw)/ratio, (peResult.getY1()-dh)/ratio);
// Imgproc.rectangle(img, topLeft, bottomRight, new Scalar(255,0,0), thickness);
List<KeyPoint> keyPoints = peResult.getKeyPointList();
// 画点
keyPoints.forEach(keyPoint->{
if (keyPoint.getScore()>PEConfig.keyPointScoreThreshold) {
Point center = new Point((keyPoint.getX()-dw)/ratio, (keyPoint.getY()-dh)/ratio);
Scalar color = PEConfig.poseKptColor.get(keyPoint.getId());
Imgproc.circle(img, center, radius, color, -1); //-1表示实心
}
});
// 画线
for (int i = 0; i< PEConfig.skeleton.length; i++){
int indexPoint1 = PEConfig.skeleton[i][0]-1;
int indexPoint2 = PEConfig.skeleton[i][1]-1;
if ( keyPoints.get(indexPoint1).getScore()>PEConfig.keyPointScoreThreshold &&
keyPoints.get(indexPoint2).getScore()>PEConfig.keyPointScoreThreshold ) {
Scalar coler = PEConfig.poseLimbColor.get(i);
Point point1 = new Point(
(keyPoints.get(indexPoint1).getX()-dw)/ratio,
(keyPoints.get(indexPoint1).getY()-dh)/ratio
);
Point point2 = new Point(
(keyPoints.get(indexPoint2).getX()-dw)/ratio,
(keyPoints.get(indexPoint2).getY()-dh)/ratio
);
Imgproc.line(img, point1, point2, coler, thickness);
}
}
}
//服务器部署:由于服务器没有桌面,所以无法弹出画面预览,主要注释一下代码
HighGui.imshow("result", img);

// 多次按任意按键关闭弹窗画面,结束程序
if(HighGui.waitKey(1) != -1){
break;
}
}

HighGui.destroyAllWindows();
video.release();
System.exit(0);

}

public static List<PEResult> nms(List<PEResult> boxes, float iouThreshold) {
// 根据score从大到小对List进行排序
boxes.sort((b1, b2) -> Float.compare(b2.getScore(), b1.getScore()));
List<PEResult> resultList = new ArrayList<>();
for (int i = 0; i < boxes.size(); i++) {
PEResult box = boxes.get(i);
boolean keep = true;
// 从i+1开始,遍历之后的所有boxes,移除与box的IOU大于阈值的元素
for (int j = i + 1; j < boxes.size(); j++) {
PEResult otherBox = boxes.get(j);
float iou = getIntersectionOverUnion(box, otherBox);
if (iou > iouThreshold) {
keep = false;
break;
}
}
if (keep) {
resultList.add(box);
}
}
return resultList;
}
private static float getIntersectionOverUnion(PEResult box1, PEResult box2) {
float x1 = Math.max(box1.getX0(), box2.getX0());
float y1 = Math.max(box1.getY0(), box2.getY0());
float x2 = Math.min(box1.getX1(), box2.getX1());
float y2 = Math.min(box1.getY1(), box2.getY1());
float intersectionArea = Math.max(0, x2 - x1) * Math.max(0, y2 - y1);
float box1Area = (box1.getX1() - box1.getX0()) * (box1.getY1() - box1.getY0());
float box2Area = (box2.getX1() - box2.getX0()) * (box2.getY1() - box2.getY0());
float unionArea = box1Area + box2Area - intersectionArea;
return intersectionArea / unionArea;
}
}

姿态识别模型提取链接,
通过网盘分享的文件:yolov7-w6-pose-nms.onnx
链接: pan.baidu.com/s/1UdAUPWr1… 提取码: du6y


后言


就像原作者说的,不是每个同学都会python,不是每个项目都是python语言开发,不是每个岗位都会深度学习。

希望java在AI领域能有更好的发展


作者:北冥有鱼518
来源:juejin.cn/post/7413234304278970404
收起阅读 »

为什么很多程序员会觉得领导没能力

相信很多人在职场里待久了,都会遇到自己觉得比较差劲的领导,这些人可能除了向上管理能力很强外(会舔老板),其他能力在你看来都挺一般,专业能力一般,超级缝合怪--上级给他的任何任务他都能分配给你们,然后他再缝合一遍完事。 那么遇到这种领导我们该怎么办呢?多数人想到...
继续阅读 »

相信很多人在职场里待久了,都会遇到自己觉得比较差劲的领导,这些人可能除了向上管理能力很强外(会舔老板),其他能力在你看来都挺一般,专业能力一般,超级缝合怪--上级给他的任何任务他都能分配给你们,然后他再缝合一遍完事。


那么遇到这种领导我们该怎么办呢?多数人想到的是跳槽,这确实是一个解法,但你跳到下家公司也保不齐会有这样的领导呀,今天咱们讨论的这个话题就先把条件限定成你不能跳槽,这个时候你该采用什么方法让自己的上班体验变好一些。


多元化自己的评估标准


首先,不能用鄙视的眼光去看待你的领导,觉得他只会舔老板(能舔、会舔也是一种很强的能力呀),有的时候你觉得你领导能力不行,很有可能是因为你的能力评估标准太单一了。


他或许在工作的某个方面不如你,但是他必定在某些方面有自己的长处,努力发现他的长处,认可他的长处,学习他的长处,可以更有助于你和他的相处,也有利于你的进步。


社会是一个大熔炉,你需要的不仅仅是业务能力和展现的舞台,也需要与社会中不同个体的和谐共处。包容、接纳,都是立身处世的能力。


学会变通和沟通,满足领导的存在感


领导之所以会在很多工作上提意见、瞎指挥、乱指挥,更多的情况可能是他知道自己对工作不熟悉,但觉得自己是领导,会有自己独特的见解,想刷自己的存在感。这种情况下,要学会满足领导的存在感。


举个例子说,你在工作中,领导过来给你提了个意见,这个意见明显是不合适的,那你就可以说,“领导,这个思路好,我们之前没往这个角度想,可以从这个角度延展一下……。”他走了,还不是我们自己把控,毕竟他只是过来刷个存在感的,只要最后的方案让客户满意,业绩给领导,把一些光环放在他身上,让他觉得他起到了作用,这些方案和他有关,他通常也不会计较了。


摸清领导管理的思想和套路


说到这里,找到领导心中的关键因素,是非常必要的。在一个项目里,员工承担的通常只是局部,而领导看的是整体,由于高度不同,所以你们考虑的关键因素是不同的。


所以你要知道领导心里到底想要的是什么,提前做好这方面的预期和准备,以及针对领导提出的你们没有考虑到的方面要虚心接受(毕竟领导跟高层接触的更多,有些战略方向上的事情他们会更清楚)。 


比如说,你是一个小编,你在意的是按时完成写作任务、及时发表、赚取眼球,而你的领导主编可能更在意的是你文章的各种数据真实性、转化人群、是否会产生舆情、是否zzzq这些。所以,要搞清领导在意的重要维度,工作才能更有效。


这里有三句话分享给大家:



  • 要能够分清你可以改变的事、无法改变的事;

  • 不去抱怨你服务改变的事;

  • 把精力用在你可以改变的地方。


你的上司,是你改变不了的,但你自己,是可以把握的。当然这篇文章也不是教你怎么委屈自己,只是提供一个不同的角度来讨论"领导不行” 这个事情,以及让你在无法立刻更换环境时,该怎样让当前的环境变得不那么恶劣。


想跳槽的同学还是应该按部就班的准备,骑驴找马有更合适的地方该跳就跳,跳过去了说不定今天学到的这些还能用的上……。


作者:kevinyan
来源:juejin.cn/post/7357911195946336293
收起阅读 »

留在家乡还是 奔向一线城市

前言导读 这个专题主要是发表一些生活的感想感悟,言论主观得一塌糊涂哈 各位网友有自己的想法都可以分享发出来。 为什么要写这个话题 1 第一个原因 父母养老问题 父母养老的问题, 相信各位北漂 深漂的游子都比较有感触吧。 自己远在深圳 广州 北京 上...
继续阅读 »

前言导读


这个专题主要是发表一些生活的感想感悟,言论主观得一塌糊涂哈 各位网友有自己的想法都可以分享发出来。




  • 为什么要写这个话题




  • 1 第一个原因 父母养老问题



父母养老的问题, 相信各位北漂 深漂的游子都比较有感触吧。 自己远在深圳 广州 北京 上海 等地工作。一旦有个什么事情,自己也很难第一时间赶回去处理。即使回来了 也是各种奔波。身心巨累,所以这时候很多人,在这个时候犹豫了。是否考虑回去。




  • 2 第二个原因 生活节奏



经历过一线城市高压力快节奏的生活,自己再次回到小县城,之后那种骑着小电驴能到处游玩。 能够干着轻松的工作,能陪伴自己的家人。这种鲜明对比 好似在疫情之后房价暴跌之后愈发明显。 好像去到省城 去到一线城市,不再是我们唯一的选择。似乎对了很对选择。




  • 3 第三个原因 居住环境和工作环境



工作的规划的居住问题, 相对一线贵的让头疼的房价 小县城好像也有他独特的优势。虽然在工作靠的
更多的是人情关系, 人情世故貌似是这样的必修课,当然这些也是一部分年轻人比较反感的, 这个见仁见智, 有些人被迫接受这些, 有人反感这些就远离这些。这都很正常。


具体自己所见 所闻


从一线新家回去一次的经历


image.png


image.png


image.png


image.png


image.png


上图可以看到 回一次家过程非常曲折 新塘站 - 广州白云站 -武昌火车站- 汉口北地铁站 - 红安城乡公交总站。经历了 九九八十一难 我才到达老家。感觉非常折磨人, 此刻我是真的有点动摇了,是否自己几年的前的决定是个错误的决定。 有时候也感慨每年就回来那么两次。忍忍就好了,一切都会过去。


和人交流想法转变


但是这次回来住在表弟家里就在晚上的时候,吃完晚饭 ,去他堂哥家里 休息了,也是交流了很多, 也都是程序员但是他们选择不去武汉留下老家了, 可以避开那些快节奏的生活和高压力。 虽然收入相对可以减少些。 当时就很感触这个不正是我们想要的稳定的生活吗。 可能 20 多岁的时候, 那时候想着有很多很多目标, 几年几年做到某一个高度。 要是实现的自己的某个目标啥的, 但是我们发现,那些真的能成的毕竟是少数, 大多数人还是选择了相对平衡和稳定的生活。


抉择问题


各位好像都有遇到我们,高考要上什么样的学校,选择什么样的专业都不是自己选的,都是父母为自己选择,好像都没有自己为自己的人生真正负责过, 等自己长大了,有一些成就后,想定居哪里以后在哪里发展, 和什么样的人结婚生儿育女,好像都是父母长辈替我们决定的。 这时候内心就会有很多疑问,只要自己决定还是说,尊重父母意见, 以前我很不理解一些选择, 为什么可以留在一线还要回去,现在才知道有部分是权衡利弊的选择,有部分人也只是为了选择而选择 或者是为了父母的选择,
父母都只想子女留在身边(这个想法个人看来有点自私,但是也是目前现状),经历这么多的事情,也是切身感受到,人跟人观念的不同,我们既要找到和我们同频共振的那部人人, 同时也要能接受和尊重那些跟我们不同观念人,因为这个世界允许存在差异,正是因为存在差异才会有不同的观点想法。 也会让我们能多思考怎样能过好自己的生活 ,怎样才能规划好自己的未来。


小县城慢节奏优点


小县城没有快节奏 高压力,相对比较适合那些慢节奏生活的人, 也方便照顾年迈的父母, 如果一旦一个什么事情都可以随时有个照应。这些都是在一线头痛的事情。


image.png


image.png


一线职业发展优点


一线城市有更多的就业机会,和各种线下活动。技术交流,能让自己职业发展更上一层楼。也能节假日去看看各种游玩地区 。


image.png


image.png


image.png


最后总结:


无论是选择留在家乡小县城还是奔向一线城市,我们都要承担对应带来的负面的后果,也能享受对应能带来的福利。这些就看自己选择,如果像我这样的情况父母身体真的很差,建议可以送去敬老院 然后自己再去拼搏 或者留在自己身边 这个看父母自理能力和我们自己是否愿意长期照顾年迈的父母了,以上的观点都是我自己主观分享不代表所有人 各位可以结合自己实际情况做出最佳选择。也预祝各位 2024 国庆节快乐祖国成立 75 周年普天同庆。


作者:坚果派_xq9527
来源:juejin.cn/post/7421185520339124287
收起阅读 »

当我入手一台 MacBookPro 之后

从 13 年实习开始,开发环境从 Ubuntu 转战 MacOS,中间换了好几次电脑,每次都是直接用 Mac 自带的 Time Machine 来迁移数据,仅需一块移动硬盘或者一根 type c 线,经过一个晚上的数据迁移,第二天就可以用新电脑工作了,除了配置...
继续阅读 »


从 13 年实习开始,开发环境从 Ubuntu 转战 MacOS,中间换了好几次电脑,每次都是直接用 Mac 自带的 Time Machine 来迁移数据,仅需一块移动硬盘或者一根 type c 线,经过一个晚上的数据迁移,第二天就可以用新电脑工作了,除了配置升级了,几乎感受不到换电脑的乐趣,并且升级过程中,也积累了不少系统升级的旧疾,这次从Intel芯片到 M3 Max 芯片,我打算从零开始,重新蒸腾一番,顺带更新一下工具库,说干就干,Go!
先介绍下新电脑的配置



  • 太空黑:从经典的银色、到太空灰,这次体验一下太空黑

  • 14 寸:用了大概 3 年的 14 寸,就一直用 15/16寸,因为这台不是用于办公,考虑携带方便,所以入手 14 寸(大屏幕肯定爽,但是在家主要也是外接显示器)




  • M3 Max:想要体验一下本地大模型,直接入手 Max(找个借口🤐)

  • 64G 内存:一直有在 macbook 上装虚拟机(Parallels Desktop)运行 Windows的习惯,升级了一下内存

  • 2TB SSD:以前 512 的时候,由于各种 npm 包、docker 镜像,还是隔一段时间就要重启一下、硬盘清理等方式来释放空间,一步到位





后面还换过几台,从最开始的 touchbar ,蝶式键盘,再到取消 touchbar,这时候更多的是工作工具的更换,连拍照的激情都没有🥱🥱


开发工具


科学上网工具


作为开发,第一件事情是需要一个趁手的科学上网工具,不然类似下载 Google Chrome、安装 Homebrew 等基础的工具都会十分麻烦
我的科学上网工具,支持按照规则配置自动代理,同时也支持终端代理,以下是终端代理,这里不方便推荐具体工具


# 防止终端命令无法确定是否需要科学上网,不建议把这个命令持久化到 bashrc/zshrc,在需要时打开终端输入即可
export https_proxy=http://127.0.0.1:1235 http_proxy=http://127.0.0.1:1235 all_proxy=socks5://127.0.0.1:1234

Xcode


Xcode 命令行工具,许多开发工具和依赖所需的基础,运行一下命令,选择安装,稍等一会即可


xcode-select --install

Homebrew


通过 homebrew 来管理一些开发工具包,如 git、node等等,由于需要下载 github 地址,这里需要借助你的翻墙工具


/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

然后按照提示,把命令加到 PATH


(echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> ~/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"

Git/Tig


brew install git
# brew install git-gui
# brew install tig 个人是 vim 用户,偏向这种终端 gui
# 这里会自动安装 zsh 的自动补全工具,后续安装 zsh 可用
# /opt/homebrew/share/zsh/site-functions

安装 git 和 tig 都会默认新增 zsh 的补全方法,好吧,这是提醒我要立马安装 zsh
tigrc 可以用来自定义 tig 的一些配置和快捷键绑定


A sample of the default configuration has been installed to:
/opt/homebrew/opt/tig/share/tig/examples/tigrc
to override the system-wide default configuration, copy the sample to:
/opt/homebrew/etc/tigrc

zsh completions and functions have been installed to:
/opt/homebrew/share/zsh/site-functions

在任意已经初始化 git 的项目,打入 tig ,然后你就可以使用 vim 的方式来操作了 jk 等等

另外,使用 git 我还会额外安装两个 git 相关的小插件
一个是 tj 大神开发的 git-extras


brew install git-extras

# 添加到 ~/.zshrc
source /opt/homebrew/opt/git-extras/share/git-extras/git-extras-completion.zsh

详细的命令可查看文档,我比较常用了是 git summary、git undo、git setup

然后通过git 的 alias 来实现一个自定义的命令,git up 来实现每次切换到一个仓库时,有意思的更新一下最新代码


git config --global alias.up '!git remote update -p && git pull --rebase && git submodule update --init --recursive'


iTerm


实现通过 command + ecs 键,快速切换显示/隐藏 iTerm



  • 设置默认终端

  • 安装 shell integration




  • 选配色:Solarized

  • 安装 oh-my-zsh


sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"


  • 修改主题,配置插件等等


brew install zsh-syntax-highlighting
brew install zsh-autosuggestions
brew install autojump
brew install fzf

#ZSH_THEME="robbyrussell"
#ZSH_THEME="agnoster"
#ZSH_THEME="miloshadzic"
#ZSH_THEME="sunrise"
# ZSH_THEME="ys"
ZSH_THEME="gnzh"

plugins=(git ruby autojump osx rake rails lighthouse sublime)
plugins=(bgnotify)
plugins=(web-search)
plugins=(node)

source /opt/homebrew/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
source /opt/homebrew/share/zsh-autosuggestions/zsh-autosuggestions.zsh
[ -f /opt/homebrew/etc/profile.d/autojump.sh ] && . /opt/homebrew/etc/profile.d/autojump.sh
source <(fzf --zsh)

这就起飞了!看看效果


Docker Desktop


作为开发,docker 技能必不可少,mac 下直接使用 docker desktop,可以省掉很多事情,特别是当你如果需要在本地跑 k8s 环境时,直接勾上 Enable Kubernetes 即可;另外新版本查看镜像,也可以扫描镜像每一层是否有安全漏洞,十分方便


VSCode


vscode 不仅适合前端开发,对于 Go、Rust 等开发者,整体体验都不错。安装后的第一件事,就是把 code 命令加到 Terminal

然后第二件事就是安装 github 的 Copilot 插件,开发、看源码现在是少不了它了

第三件事就是在 vscode 开启 vim 模式(安装 vim 插件)从 vim - sublime - vscode,一直保留 vim 的使用习惯,改不掉了😂
其他的就是各种高亮、开发辅助插件,大家按需安装即可


其他



  • 前端

    • NVM:node 版本管理

    • pnpm:上一台电脑只有 512G,在动不动就几个 G 的前端项目,硬盘一直告警,至此只用 pnpm



  • Go

    • GVM: go 版本管理

    • GoLand:虽然 vscode 可以开发 go,但是整体体验还是比不上收费的 goland




环境搭建可参考 Go + React 指北


效率工具


ChatGPT


说到效率工具,ChatGPT 绝对是提高效率神器,从日常问题到开发、图片生成、画图等等,哦,还可以帮忙挑西瓜🍉


对了,用了苹果芯片,ChatGPT app 直接通过 option + space 即可随时调出,支持实时对话、支持截屏问问题等等,好用程度大幅上升⬆️⬆️⬆️


Bartender($)


吐血推荐,让你状态栏更加一目了然
支持自定义显示哪些 icon,配置哪些 icon 始终不显示,哪些第二状态栏显示

快捷键切换第二状态栏,一下子清爽颜值高


iStat Menus($)


拥有时刻关注着网速、CPU使用率、内存使用率的强迫症,绝对不少


Yoink


当你要把一个文件从一个地方移到另外一个地方时,当你想快速复制一张图片时,剪切板记录、跨设备文件接力等等,这个小小的工具都能帮助你
有时候通过截屏软件截图,可以一次性把需要的截屏操作完,然后在剪贴板直接拖下来使用,十分方便!


BettersnapTool


一款小而美的工具,用来快速调整你的窗口,比如当前窗口在两个显示屏直接切换;全屏,左右分屏等等


iShot


本来我一直使用 Skitch 的,但是这次切换新电脑之后,发现它下架了,之前有朋友推荐了,也使用了一段时间,感觉很不错,除了普通的截图,还有长截图、带壳截图;还有其他的小工具,官方宣传是
截图、长截图、全屏带壳截图、贴图、标注、取色、录屏、录音、OCR、翻译一个顶十个,样样皆优秀!


Draw.io


好吧,这个绝对画图神器,日常写文档几乎离不开他,在线版直接打开即可使用,也可以安装 vscode 插件,不过我还是习惯下载一个 app,这样本地的文件,直接打开即可使用
距离成为架构师,你只差一个 draw.io


Parallels Desktop


如果你有使用 Windows 的诉求,那么我建议你花点钱买个 pd,融合模式一开,原来我的 16 年的机器,玩个魔兽、英雄联盟完全没问题
安装直接点击下载 Windows 11,网速好的话,10 来分钟就安装成功了

融合模式,应用和直接使用 mac 的应用没任何差别

全屏模式,可以看到截图的时候有一部分黑色,应该是没有兼容刘海屏的原因


Markdown 编辑器


Quiver,原来所有的笔记、文档基本都靠它来记录,21 年的时候作者停止维护了,再加上使用纯 markdown 工具,还需要自己找图床,最后都转到语雀、飞书等在线文档
中间还用过其他的、Mweb、Typora 等等,如果自己搭建图床,推荐使用 Typora


image-20240802223626203


image-20240802223739246


image-20240802223841320

Mweb 包含PC 和 移动端,通过 iCloud 同步,也是十分方便!


图床工具


原来写 markdown 的时候,使用的是微博免费的图床,2 年后,然后发现图片都失效了!失效了!


所以,图床还是自己维护比较靠谱!


PicList,免费开源,我自己是购买了阿里云按量付费的 OSS,简单配置一下 aks,即可上传图片,配合 Typora,轻松完成写作


image-20240802224136523


配置好之后,图片拖到 markdown 编辑框,即可实现自动上传


image-20240802224555813


BreakTime 定时提醒工具


为了你的健康,你可以让电脑提醒你,每隔30分钟休息一下,倒杯水,看看风景


DaisyDisk (付费)磁盘空间,文件大小分析工具


作为只能买 256G 的屌丝,每天困扰我的一件事就是磁盘空间不足
现在我是 2T 了,可以不用了
也可以使用 腾讯柠檬用过一段时间,也很好用


微信输入法


搜狗输入法、RIME、百度输入法(作恶多端,还用)
上一次推荐,我还是使用搜狗输入法,有朋友推荐微信输入法,体验了一把,简洁、功能齐全,所以手机、PC 全部改用微信输入法
推荐跨设备复制黏贴,速度比苹果自带的快了许多


思维导图:Xmind, MindNode


脑图应用,一般在项目开发过程中用于 需求分解,Model Design 等等。


其他小应用



  • Caffeine

  • Manico, 在 macOS 强大的触摸板下,一直认为这个软件没什么用, 而且快捷键还有很多冲突

  • tmate, 搞基神器,结对编程,定位问题必备神器


Chrome 插件推荐



  • Vimium, 通过键盘快捷键操作网页,比如打开,关闭,查找书签等等

  • FeHelper(前端助手):JSON自动格式化、手动格式化,支持排序、解码、下载等,更多功能可在配置页按需安装

  • Axure RP Extension for Chrome

  • Grammarly for Chrome,语法检查

  • Octotree,github源码查看神器

  • OneTab,节省高达95%的内存,并减轻标签页混乱现象

  • Postman Interceptor

  • React Developer Tools

  • Redux DevTools

  • Yet Another Drag and Go:超级拖拽.向四个方向拖拽文字即可进行相应的搜索.拖拽链接可在前台/后台,左侧/右侧打开

  • 掘金

  • Sider: ChatGPT 侧边栏 + GPT-4o, Claude 3.5, Gemini 1.5 & AI工具”的产品徽标图片 Sider: ChatGPT 侧边栏 + GPT-4o, Claude 3.5, Gemini 1.5 & AI工具

  • xSwitch:前端开发代理神器,在线 debug 问题,把线上资源代理到本地,方便复现问题


作者:Justin_lu
来源:juejin.cn/post/7398351048777842729
收起阅读 »

BOE(京东方)“向新2025”年终媒体智享会落地深圳 “屏”实力赋能产业创新发展

12月27日,BOE(京东方)“向新 2025”年终媒体智享会的收官之站在创新之都深圳圆满举行,为这场为期两周、横跨三地的年度科技盛会画上了完美句号。活动期间,全面回顾了 BOE(京东方)2024年在多个关键领域取得的卓越成绩,深入剖析其在六大维度构建的“向新...
继续阅读 »

12月27日,BOE(京东方)“向新 2025”年终媒体智享会的收官之站在创新之都深圳圆满举行,为这场为期两周、横跨三地的年度科技盛会画上了完美句号。活动期间,全面回顾了 BOE(京东方)2024年在多个关键领域取得的卓越成绩,深入剖析其在六大维度构建的“向新”发展格局,精彩呈现了以“屏”为核心搭建起的技术引领、伙伴赋能以及绿色发展等平台,全方位赋能全球生态合作伙伴,充分彰显BOE(京东方)作为全球领先的物联网创新企业的引领地位与责任担当。深圳活动现场,BOE(京东方)执行委员会委员、副总裁刘竞以及 BOE(京东方)副总裁、首席品牌官司达亲临现场,发表了主旨演讲。此次系列智享会的成功举办,进一步加深了与会嘉宾对 BOE(京东方)发展理念、技术实力与创新成果的认知和理解,也为BOE(京东方)新一年的发展拉开了充满希望和活力的序幕。

经过三十余年创新发展,秉持着对技术的尊重和对创新的坚持,在“屏之物联”战略指导下,BOE(京东方)从半导体显示领域当之无愧的领军巨擘迅速蝶变,成功转型为全球瞩目的物联网创新企业,并不断引领行业发展风潮。面对下一发展周期,BOE(京东方)将从战略、技术、应用、生态、模式、ESG六大方面全方位“向新”突破,以实现全面跃迁,并为产业高质发展注入强劲动力。

战略向新:自2021年“屏之物联”战略重磅发布以来,BOE(京东方)又于2024年京东方全球创新伙伴大会(BOE IPC·2024)上发布了基于“屏之物联”战略升维的“第N曲线”理论,以半导体显示技术、玻璃基加工、大规模集成智能制造三大核心优势为基础,精准布局玻璃基封装、钙钛矿光伏器件等前沿新兴领域,全力塑造业务增长新赛道。目前,玻璃基封装领域,BOE(京东方)已布局试验线,成立了玻璃基先进封装项目组,实现样机产出;钙钛矿领域,仅用38天就已成功产出行业首片2.4×1.2m中试线样品,标志着钙钛矿产业化迈出了重要一步。

技术向新:2021年,BOE(京东方)发布了中国半导体显示领域首个技术品牌,开创了产业“技术+品牌”双价值驱动的新纪元。以技术品牌为着力点,BOE(京东方)深入赋能超5000家全球顶尖品牌厂商和生态合作伙伴,包括AOC、ROG、创维、华硕、机械师、雷神、联想等,助力行业向高价值增长的路径迈进,也为用户提供了众多行业领先、全球首发的更优选择。BOE(京东方)还将全力深化人工智能与半导体显示技术以及产业发展的深度融合,并在AI+产品、AI+制造、AI+运营三大关键领域持续深耕,并依托半导体显示、物联网创新、传感器件三大技术策源地建设,与产业伙伴和产学研合作伙伴共同创新,为产业高质量可持续发展保驾护航。

应用向新:BOE(京东方)不仅是半导体显示领域的领军企业,也是应用场景创新领域的领跑者,BOE(京东方)秉持“屏之物联”战略,以全面领先的显示技术为基础,通过极致惊艳的显示效果、颠覆性的形态创新,为智慧座舱、电竞、视觉艺术、户外地标等场景注入了新鲜血液,带给用户更加美好智慧的使用体验。以智慧座舱为例,根据市场调研机构Omdia最新数据显示,2024年前三季度BOE(京东方)车载显示出货量及出货面积持续保持全球第一,在此基础上BOE(京东方)还推出“HERO”车载场景创新计划,进一步描绘智能化时代汽车座舱蓝图。

生态向新:BOE(京东方)持续深化与电视、手机、显示器、汽车等众多品牌伙伴的合作,共同打造“Powered by BOE”产业生态集群,赢得众多客户的认可与赞誉。与此同时,BOE(京东方)还持续拓展跨产业生态,通过与上海电影集团、故宫博物院、微博等文化产业领先机构展开跨界合作,以创新技术赋能传统文化艺术与影像艺术。此外,通过战略直投、产业链基金等股权投资方式协同众多生态合作伙伴,通过协同合作、资源聚合共同构筑产业生态发展圈层。

模式向新:为适配公司国际化、市场化、专业化的长远发展,BOE(京东方)持续深化“1+4+N+生态链”的业务发展架构,以及“三横三纵”组织架构和运营机制。在充分市场化和充分授权的机制保障下,形成了以半导体显示核心业务为牵引,传感、物联网创新、MLED业务、智慧医工四大高潜航道全面开花,聚焦包括智慧车联、工业互联、数字艺术、3D光场等规模化应用场景,生态链确保产业上下游合作伙伴协同跃迁的“万马奔腾”的发展图景。此外,BOE(京东方)还鼓励员工创新创业,通过激发人才创新热情,共同为集团发展注入强劲内生动力。

ESG向新:2024年,BOE(京东方)承诺将在2050年实现自身运营碳中和,并通过坚持“Green+”、“Innovation+”、“Community+”可持续发展理念,推动全球显示产业高质永续发展。“Green+”方面,BOE(京东方)依托超过16 家国家级绿色工厂、显示领域唯一1家国家级无废工厂、1 座灯塔工厂及2座零碳工厂,以绿色产品、制造与运营践行低碳路径;“Innovation+”方面,BOE(京东方)凭借全部为自主创新的9万件专利的行业佳绩,以及技术策源地、技术公益池等举措,携手产业上下游伙伴协同创新;“Community+”方面,BOE(京东方)在教育、医疗、环境等公益领域持续投入,积极履行社会责任,例如在“照亮成长路”公益项目中,BOE(京东方)十年间在偏远地区建设的智慧教室已经突破120所。

BOE(京东方):屏即平台赋能创新

在新一轮数智化浪潮中,全球显示行业的龙头企业 BOE(京东方)以屏为核心,充分发挥技术引领作用,积极赋能合作伙伴,并秉持绿色发展理念,全力构建产业高质量、可持续发展的创新生态平台,引领行业在高速发展的科技浪潮中稳步前行,为全球用户缔造更加智能美好的生活体验。作为 BOE(京东方)全球创新生态布局的关键一环,珠三角区域不仅是其创新要素汇聚的高地,更是其全球化发展的重要窗口与强大驱动力,为“屏之物联”战略落地提供了有效支撑。

技术引领方面,BOE(京东方)多年来始终秉持对技术的尊重和对创新的坚持,致力于推动显示技术全面向新发展,以完美画质、AI+显示、无界形态、氧化物(Oxide)关键技术等关键领域,持续挖掘“屏”在物联网领域的无限潜力。

完美画质,BOE(京东方)深入洞察用户真实需求,基于ADS Pro技术优化升级的高端LCD解决方案UB Cell,所呈现的完美画质可以媲美OLED,堪称LCD显示技术发展的重要里程碑。目前,BOE(京东方)已携手合作伙伴推出了一系列搭载UB Cell高端液晶电视旗舰产品,引领液晶显示技术升级风向标;

AI+显示,BOE(京东方)在软硬件层面均已为AI的深度应用构筑完美平台,不仅实现了光感、温感、NFC等传感器件的屏内集成,还开发了屏幕局部刷新、远端功能监测等软件技术,显著增强了用户感知,提升了交互体验;

无界形态,BOE(京东方)作为国内在柔性OLED领域布局早、技术优、市场应用广的领军企业,在材料、工艺等领域具备全面优势,不仅在屏幕轻薄化、超清化方面性能卓越,更能够实现折叠、卷曲等形态变化,同时不断探索屏下摄像、屏下指纹、3D touch等多功能的智慧集成,更是打造出行业首款三折屏等具有行业里程碑意义的产品,带领用户迈入更多变、更智能的未来生活;

氧化物技术,BOE(京东方)在产能、技术以及产品性能上均位居行业领先地位,凭借高刷新率、高分辨率、低功耗等优势,在未来高端IT产品领域展现出广阔的应用前景。

伙伴赋能方面,BOE(京东方)始终以合作共赢为宗旨,高效整合资源,与生态伙伴携手向新发展,共筑高价值发展空间。BOE(京东方)坚持第一时间捕捉行业及市场需求动向,通过内部研发及运营保障机制,完成技术开发应用,组织建设和人才培养,完善流程、数据、组织以及IT能力建设,输出市场化、专业化、国际化的服务能力,并联动上下游及科研机构等生态伙伴,共同探讨“以人为本”的最优解决方案,深度拓展更多高端应用场景;同时,持续进行智能制造实践探索,确保稳定交付,赋能终端伙伴,使其能更好融入更真实、更丰富的消费者使用场景,实现产业高价值增长。

绿色发展方面,BOE(京东方)早已将可持续发展刻入企业基因,融入企业日常经营与管理的全链路,从绿色规划、低碳设计到碳足迹量化认证等各个环节,全力实现极致降碳目标。原材料环节,BOE(京东方)通过打造绿色供应链,积极使用可回收、可降解以及清洁材料,为产品低碳化发展奠定坚实基础;生产制造阶段实现全面绿色低碳;产品流通及回收阶段,BOE(京东方)已完成49个产品的碳足迹认证,凭借可回收、可降解的绿色材料,在产品的全生命周期中均实现了最大化降碳,让“科技创新+绿色发展”成为产业升级的主旋律。

“向新2025”年终媒体智享会,是BOE(京东方)2024创新营销的收官之作和全新实践,系统深化了大众对BOE(京东方)品牌和技术创新实力的认知与理解。近年来,BOE(京东方)通过多种创意独具的品牌破圈推广,包括“你好BOE”系列品牌线下活动、技术科普综艺《BOE解忧实验室》等生动鲜活地传递出BOE(京东方)以创新科技赋能美好生活的理念,为企业业务增长提供了强大动力,也为科技企业品牌推广打造了全新范式。BOE(京东方)“向新2025”主题系列活动已先后于上海、成都、深圳成功举办,为BOE(京东方)2024创新传播划上圆满句号。

面向未来,BOE(京东方)将胸怀“Best on Earth”宏伟愿景,坚持“屏之物联”战略引领,持续推动显示技术和物联网、AI等前沿技术的深度融合。从提升产品视觉体验到优化产业生态协同,从升级智能制造体系到践行社会责任担当,BOE(京东方)将砥砺奋进、创新不辍,为全球用户呈献超凡科技体验,领航全球产业创新发展的新篇章。

收起阅读 »

坚持背单词2000天,能带来哪些变化

近三年前,我写了一篇背单词坚持1000天的小总结,从三个方面整理了这坚持给我带来的变化: 一是背单词最本质用处,它让我认识的英文单词多了许多,我甚至能试着看看英文原版书;二是一种心理暗示,既然我能坚持每天背单词,那看书、摸球或是锻炼,也将是可以坚持的;三是多出...
继续阅读 »

近三年前,我写了一篇背单词坚持1000天的小总结,从三个方面整理了这坚持给我带来的变化:


一是背单词最本质用处,它让我认识的英文单词多了许多,我甚至能试着看看英文原版书;二是一种心理暗示,既然我能坚持每天背单词,那看书、摸球或是锻炼,也将是可以坚持的;三是多出一种对未来的展望,我很期待,背单词到2000天、5000天时我的改变。


图片


打卡1999天


时间过得真快,过完明天,我坚持背单词便满2000天了。


但当下的我,却想对1000天前的我说一句抱歉:“对不起,似乎你未来1000天的坚持,并没有为你带来更多改变,你还是你。你英文的听说读写,似乎和当时水平相差并不太远,你也并没有发展出更多的小坚持……”


当然不只有抱歉,“除了抱歉,你依然还拥有着希望。”


即便当下感受到的改变不多,我依然很期待,第3000天、第4000天、第5000天时我的改变。


从坚持背单词满1400天时起,之后的每一个100天,我都在掘金沸点上面打个卡,我很享受那种一天一天慢慢攒出一个整数值后有东西可以分享的感觉。其中,有一些骄傲,也有一点虚荣。


在第1800、1900天时,我便起了心思到2000天时再写一篇小总结。之后大概每隔两三周,我都会想一想这总结中该写些怎样内容:


“考研词汇对我来说很简单,进入复习阶段,一天背80个,有时候前面一个不错,到最后几个单词,我会很紧张。”


“背单词的时间,一直在变化。大多数是在出门等电梯,独自吃早餐或是吃完早餐后赶地铁、去工位的步行路上。那些长一些的独处时间,我更愿意用来看书,而不是背单词。”


(边走路边看手机,当然是一个不好习惯。)(于此处批评自己让我想到我会在某些时候进入“成人状态”,会对他人提出建议如“少喝些酒”“早点睡”之类,我隐隐感觉这种建议方式似乎正让我的行事方式越来越固化,晚点睡怎么了嘛?)(我简直要变成括号之神。最后这个括号说我思维杂乱,发散太快:我到底要不要删掉这几个括号呢?我决定不删。)


“《百词斩》,一直在进步。除了广告越来越多之外,他们还推出专门背单词的学习机,他们在单词详细界面添加了近义词、反义词、形近词;除了看图选词,他们还推出了汉译英、听音选词等更多帮助强化记忆的方式。”


“好几位朋友问过我,你背单词的目的是什么?出国?和外国人交流?还是怎样?我当时给予的答复都是:‘好像都不是,背单词对我来说只是一种提醒,提醒我别忘记坚持’。”


“背单词对我来说,似乎也变成跟吃饭睡觉一样,是每天都会做的事情,已经可以不用‘坚持’就能持续下去,这使得我已经连续561天不间断。这种稀疏平常的每日行为,似乎没什么总结好写的。”


一周以前,我决定本周公众号的更新主题为“坚持背单词2000天”,翻阅过去想法的汇集,却只有上面寥寥几句。这几句,只是一些零碎想法,当下的我似乎想要表达更多些。我在碎片时间想这个话题,最终冒出一个稍显负面但我却很想知道答案的问句:坚持背单词这么久,是为了什么呢?


这问题甚至被我更扩大些:坚持看书是为了什么?坚持写东西是为了什么?总之,坚持,是为了什么呢?


我将自己过去靠坚持开始到现在还一直在持续的事情一一列举。


坚持最久的一件事,是每天都写日记,它始于15年10月,累积8年半时间。我最初的想法,是“记录生活中的事情,以作总结用”,日记中片段被我用作总结的很少,它更多的用处,是帮我回忆起许多忘记的场景和情绪。


坚持背单词,2000天。


坚持周更公众号3年半。周更公众号,最初是为了获得睡后收入,睡后收入每天只有几分,但它慢慢变成我生活中很重要的一部分,我较远些的目标,是想着写一本完整的延续性强的细节丰富的诉说平凡的书。写公众号为收入,为练习写作,也为总结整理自己。是的,相较日记里的随意,公众号内容是更可以称之为总结的:我想得更多也尽量想得更广更深。


坚持每天看书近3年,《微信阅读》上的记录是“连续阅读581天”。我最初看书是为了让自己有深度,让自己公众号有内容可写,现在则演变成一种爱好,一种习惯;这爱好有些不好之处是它让我很依赖作者的想法,“作者在我脑中跑马”是常发生情况。


坚持每天11点前睡觉,一年又11个月。这习惯的养成,多少和读书有些关系,首先来自于从Why We Sleep中收获的认知:睡眠好了一切都好(我又多出一点自己的理解:睡眠好说明一切都还好);然后是《习惯的力量》,暗示、惯常行为和奖赏围成一个圈,早早洗漱暗示自己想要睡觉,准点睡觉是惯常行为,第二天醒来能量满满便是奖赏。


每天做10个俯卧撑,坚持20天。每天做俯卧撑这件事情,我尝试过很多次,也放弃过很多次,今年过年回家吃饭毫不控制导致肚子又大起来,我想借这坚持作为锻炼的入门提醒。


写日记、背单词、周更公众号、看书和睡觉,是我一直在坚持做着的事情。所以,坚持的意义到底是什么呢?


对书籍已经产生依赖的我想去找一找关于“坚持”主题的图书,简单搜索一番后没找到答案,于是只输出自己的当下理解。


首先,它是一种价值观的体现,我相信这每天的一点点积攒,是肯定会为我带来些提升的,不管是读写能力还是好的身体状态的更长时间延续。


其次,是一种人生不会停止的希望,我坚持做的这些事情,不管四十五十甚至六十七十岁,都可以一直进行下去;我很期待看到五年十年甚至三十年后还依然做着这些事情的自己的样子。


然后,是提醒自己思考的工具,我该为这每一份坚持加上一个目标一个方向?比如背单词是为考研或是雅思?是不是没有方向的坚持,只是在原地转圈呢?


然后,就没有更多想法了,我只告诉自己,且继续将这几件当下自己认为对自己有用事情坚持下去。


至于坚持的意义,等下一个1000天到来时,再想想。


作者:我要改名叫嘟嘟
来源:juejin.cn/post/7352091152584376331
收起阅读 »

三十而立却未立,缺少的是女朋友还是技术能力?

作为一个从事 Web 工作 8 年来的相关人员的一点心路历程,希望我的经历能给大家带来稍许乐趣。 迷茫,特别迷茫 俗话说得好:“岂能尽如人意,但求无愧于心”,工作 8 年来,我经常这样自我安慰。不过这并不影响我也经常感觉无所适从,烦闷与迷茫。尤其是到了一些特殊...
继续阅读 »

作为一个从事 Web 工作 8 年来的相关人员的一点心路历程,希望我的经历能给大家带来稍许乐趣。


迷茫,特别迷茫


俗话说得好:“岂能尽如人意,但求无愧于心”,工作 8 年来,我经常这样自我安慰。不过这并不影响我也经常感觉无所适从,烦闷与迷茫。尤其是到了一些特殊的年月节点,这种焦虑感总是更加强烈。


那到底有什么迷茫的呢?一言以蔽之,有了对比,就有了伤害。正如标题所言,女朋友和技术能力,换一个通俗的话,也可以叫“美女与金钱”,当然更常规的说法,是“家庭与事业”。


如果简单横向对比起来,我迷茫确实看起来不意外:



  • 我好歹也是正儿八经 985 大学软件工程方向本科毕业,也算是科班出身;

  • 工作了 8 年,不仅是被同学、绝大部分同行从业人员从薪资水平、发展前景、人际交往、生活质量等各方向甩在身后,甚至都比不上复读一年考上不知名二本学校、去年才毕业的表弟;

  • 没房没车,没有成婚,还背井离乡,漂泊千里之外;

  • 日子看起来浑浑噩噩,没有什么远大志向,也没什么乐衷的兴趣……


怎么就变成这样了呢,我觉得我有老老实实、脚踏实地地做事情啊。回想自己从业这些年:



  • 从一开始的 JSP + Spring MVC + MySQL 这套原始的 Java Web 开发;

  • 到当时外面还比较时髦的 MEAN(MongoDB、Express.js、Angular 和 Node.js);

  • 后来回归到 Angular + Spring 这套,然后改为现在常用的 Vue + Spring,其中还一度以为 WebFlux 会有大用;

  • 当然前几年除了做些全栈开发,还不得不兼备 K8s 相关一大套的运维技能;

  • TiDB、Redis、ES、Prometheus 什么的都要搞一搞,Flink 什么的也得弄一弄,加上一大堆第三方自动化、监控等工具的使用配置;

  • 现在没事时用 Python 写个脚本处理一些批量任务,自己搞搞 Flutter 练手自己用的 APP。


我都觉得自己还是挺厉害的,因为这些就没一个是学校里教的东西,都是出来挨打自学的。


但实际上的现状呢,我还是呆在一个电子厂里面,拿着千把块,做着鸡毛蒜皮的事情,下班就回到公司的宿舍,龟缩起来。这样 855 毫无意义的日子,居然一呆就是 8 年了。


“可怜之人必有可恨之处?”


那我当然是自以为是的可怜了,毕竟如果真得像我说的那样出色,是金子自然会发光了,也怎么可能愿意继续呆在这种地方,离最近的地铁站、火车站都要30多分钟公交的制造业工厂里面?


确实,扯开嘴巴滋哇乱叫谁不会,有什么因就有什么果了。



  • 大四的时候,跨专业自学准备心理学方向的考研,错过了秋招;没考上之后,当时的技术能力,已经不支撑找个满意的工作了。

  • 做中学,两年后的 18 年正是行业发展高潮,准备出去看看。结果年轻,血气方刚,在领导的 PUA 和自以为是没能干出一点功绩就离开,不满意,然后留下来。

  • 又之后的一年之余,已经发现技术水平和人生阅历和同行差距过大,还是骑驴找马。在得到几个 offer 之后,却不知原因突然想回老家城市,这些深圳广州的机会就莫名其妙放弃了,重庆的眼高手低又没找到满意的。

  • 之后疫情时代,在一些大城市比如 SH、SZ 等出现强烈的排外现象之后,越发想要回家。但重庆的互联网行业,和主流城市差距可太大了。当时当地政府甚至在大力发展实体制造业,老家区县招商建工厂,租 100 亩送 100 亩。

  • 疫情尾期和这两年,什么“前端已死”、行业落寞,找工作难度陡升,试想,什么样的公司会找一个 8 年工作经验的初中级前端?全栈?运维?……


去年我找工作从 5 月份找到 10 月份,沟通了 200 多个岗位,只有 20 多个接收了简历,约到 3 个网上面试,最后一个没过。除了一些需要线下面试的没法去,也有面试的匹配度也不够、岁数不够年轻等其他因素。8 年来最多就管理过不到 10 人的小团队,当然不到一年就结束了,也没有能力发展管理岗。


与自己和解是不是自欺欺人?


会不会有种“咎由自取”的感觉,我偶尔也会想:



  • 如果 18 年我去了深圳而不是听信领导的话留在了东莞这里,我的发展轨迹会不会有所改善?

  • 更有甚,如果大学不是脑袋一热为了自救去考什么心理学专业的研究生,好好学习技能找工作或者考本校,会不会又是另一番风景?

  • 甚至更早,如果当年高考没有发挥失常,或者要是考得更差一点,去个师范,实现我儿时的理想,成为一名教师,情感上是不是更能自洽?


有句网络流行语是这样说的:有人看段子,有人照镜子。曾几何时,我也这样觉得:



  • 反正现在没车没房没女友,离家又远没外债;

  • 物质能力虽不高,但消费欲望不强;

  • 不能为国家做大贡献,但也还没有给社会添乱;

  • 下班回宿舍看看视频、打打游戏、玩玩手机,偶尔出去打打球,散散步……


没有复杂的人际关系,没有太大的家庭工作压力,清闲时间也比较充足,简简单单三餐一宿,我明明很惬意的,也明明已经惬意了 8 年来。


——“你一个月多少工资?” 、“怎么才这点?”

——“你现在什么级别?” 、“怎么才这个级别?”

——“你开什么车?” 、“什么?你连驾-照都没有?”

——“你孩子几岁了?” 、“啊,你还单身?”

——“天啦,你怎么混成这样了?”
……


“人的悲喜并不相通,我只觉得他们吵闹”。“墨镜一带,谁都不爱”,我脑袋摇成螺旋桨,我飞走咯,千里之外~


未立,缺少的是女朋友?


我的看法认为:可能不是。


没有什么是一成不变的,比如年龄。我这个年纪可能不仅和更年轻的同行抢岗位抢不过,也可能在另一个相亲市场也抢不过。


虽然嘴巴上可能有的人觉得单身好,而且现在这个男女关系和社会认同比较复杂的时代。前段时候和老同学聊天聊到近况,他们都一直以为我是一个不婚主义者。当然,这并不影响我们老一辈甚至再老一辈亲戚的期盼,他们偶尔也会认为,结婚之后,一个人才成长了,他们才会放心。


你别说,你还真别说。这半年我没有写博客,也没有太多了解“行业寒冬”的发展情况,有一部分原因还真是因为年初聊见了个相亲对象。这对我是一个完全没有经历过的赛道,难得的是我感觉还不差,虽然发展极为缓慢,但还没有遇到网上那样的“悲惨经历”,当然,也可能是异地的原因。


我要经历这种事,只能是亲戚朋友帮忙,加上微信之后聊了聊,整体氛围很好,就这么聊了一个多月。本来过年的时候约个见面的,但没想到升级了,直接他们父母到我家来坐了坐,然后又邀请我父母去她家吃了饭。这在农村的意思就是老一辈的过场已经走完了,双方家长没有意见,我们能不能成、就全看自己了。


这半年虽然几乎天天都有聊,绝大多数情况下都很愉快,我也变得有些期待每次的聊天;平时也有礼尚往来,偶尔互有一些小惊喜小礼物;五一节我也回去见了面,牵牵小手,后来得知当天她出门之后才发现来例假、身体不适但还是陪我走了将近三万步的路、甚至没让我发现异样……


但问题的关键在于,似乎都没有聊到什么重点和关键的问题,没有实际的发展,感觉温度没有理想上升。仔细想想,把这每天和她相关的一两个小时删除掉,那和我这些年的日子几乎没什么区别,好像一样是挺自在惬意的,她甚至都没有给我一些需要我去翻视频学点“人情世故”才能处理的问题和情景。


本来以为是好事,但我的榆木脑袋才终于不得不承认异地一定是个大问题。所以到现在,我这股子想回家的心情就变成了内因和外因相结合的无懈可击的推力。但是却还没有热切到一拍脑袋裸辞先回家,再看天的程度。


未立,缺少的是技术能力?


我的看法认为:可能也不是。


虽然我个人学的东西有一点点乱,但怎么说呢,并不影响我自娱自乐。偶尔开发一个自用的小玩意儿,还盲目觉得挺有成就感。


而且,从实际情况来讲,现在的“技术能力”真的不是那么的重要,如果是做产品,可能一些经验能力也不可或缺,但会写代码的人,可是一抓一大把。


比如说,现在的 AI 大模型几乎是热到爆的话题,也算是百花齐放,也各自杀红了眼,现在的新东西,不说自己有个 AI,都不好意思大声讲话,新出的 PC 都挂上 AI PC,魅族都不做手机,改名为 AI 终端了。


作为普通用户和普通个人开发者角度来讲,现在使用这些大模型 API 其实非常便宜了。价格战百万 token 才几十块甚至几块钱,文本对话、文生图、图生文,也都有一定的可用性了。


但是呢,但是呢,能拿来做什么呢?有创造性的同行都已经借着东风,扶摇直上九万里了,我还在感慨好便宜啊,除了BAT平台,这两天还去零一万物、深度求索等平台注册了账号,部分也少少充值了些。但是,虽然好便宜啊,可是能用来做点什么呢?我还真的没有创造性。




既然都说到这里,也厚脸皮顺便说一句,最近弄了个比较简陋的,使用Flutter开发,支持诸多AI大模型API调用的,假装类似智能工作生活助手应用。顺带加上之前的极简记账、随机菜品、猫狗写真,放在 Github 上 Sanotsu/swmate ,虽然很简陋也不完善,但感兴趣的朋友可以看看。


智能助手功能展示.jpg


生活不需要别人来定义


可能“三十而立”意思是指人在三十岁前后有所成就。少年老成的例子很多,大器晚成的人物也不少,但到最后,这都是别人来定义的这个“立”的含义。


就如见世面,有的人是“周游列国、追求自由”,有的人是“四体勤、五谷分”,有的人的成就是“成家立业,香车美女环绕”,有的人是“著作等身”,也有的人却是成为“艾尔登之王”……外面的人看到的或许不同,但那份自己内心的快乐,是为了、也是应该能够取悦自己的。


今天是我三十岁生日,大概500天前我列了三十岁前想要完成的 10 件小事,结果当然只完成了小部分:



  • 体重减到正常 BMI 值;

  • 开发一个能自用的 APP/入门一门外语;

  • LOL 上个白金/LOLM 上个宗师;

  • 谈一次恋爱;

  • 出去旅游一次;

  • 换一份工作,换一个城市;

  • 补上自己的网站博客,整理自己的硬盘;

  • 看 10 本名著,并写下每本不多于 5000 字的读后感;

  • 完成一部中篇小说;

  • 完成 50 篇用心写的博文,可包含那 10 篇读后感。


人生是一条连续的时间线,除了起止点,中间这段旅程,并不会因为某一刻的变化而停下来,最多是慢下来;三十岁之前没有完成的事情,三十岁之后依旧可以去做;以前看得太重的东西,以后还可以改变很多;珍惜的事情太多,抱怨的时间太少;人生这段路,就这么些年,就该为自己走走看;路虽然走得不同,但走路的心情,却可以自己来定。


取悦自己真的比迎合他人要轻松和快乐许多。


共勉吧诸君,感谢垂阅。


作者:小流苏生
来源:juejin.cn/post/7385474787698065417
收起阅读 »

哭了,朋友当韭菜被割惨了

最近我的朋友,被某些知识付费坑得很惨。全程毫无干货可言。内容仅仅只适用于初级、或者说部分中级的程序员。为此,我的朋友交了大几千的学费,却收获甚微。 当然,你可能说,是你的朋友问题啊?你朋友烂泥扶不上墙,学习方法不对,别人都有很多成功的案例。什么offer收到...
继续阅读 »

最近我的朋友,被某些知识付费坑得很惨。全程毫无干货可言。内容仅仅只适用于初级、或者说部分中级的程序员。为此,我的朋友交了大几千的学费,却收获甚微。



当然,你可能说,是你的朋友问题啊?你朋友烂泥扶不上墙,学习方法不对,别人都有很多成功的案例。什么offer收到手酸,外包入大厂。




我买这些课就是为了学习,入门一些语言。知识付费很合理呀!!



于是我跟我朋友在微信彻夜长谈,有了如下分析


先说结论



请擦亮你的慧眼,你的一分一毫来之不易。不到迫不得已,才当学费



为什么这么说?


首先,不管你是想就业,还是想学习一些新的技术,网上都有例子,github上也会有前沿的项目提供学习。


类型结论
学习新技术某项技术开源出来,作为技术的布道者,恨不得你免费过去学习,然后你再发一篇文章,越来越多人学习你的技术。
就业简历包装无非就是抄抄抄,抄别人的优秀代码。github开源项目就非常合适

其次,你学费,一定要做到利益最大化。必须要有以下两点



  • 能学到大部分人都学不到的技术亮点。记住,是大部分人,一定要做到差异化

  • 能学到优秀的学习方法,push你前进。


开启慧眼


现在市面的学习机构,鱼龙混杂。,B站大学,某识xin球,某ke时jian 甚至,在某音上,都有那种连麦做模拟面试,然后引导你付费学习。


就业环境不好,买方市场竞争激烈,某些人就抓住你的焦虑心理,坑你一把。回想你的求学生涯,是否也有类似被坑经历?醒醒吧,少年。能救你的,只有你自己


当然,小海也会有潜龙。不可否认,知识付费为我们提供了便利性。



  • 原本散乱无章的知识点,人家给你整理好了,你尽管就是学习,实践

  • 面对焦虑,你觉得很迷茫,需要一个人指点你前进

  • 能认识更多同样诉求的人,为以后学习,就业,甚至做生意提供可能


但是,某些不法分子,就是抓住你的这个心理,疯狂ge你韭菜。什么10块钱知识手册,19.9面试题,100块钱的项目视频。天天一大早,就转发一些公众号到你群上,dddd。


这些内容,不是说没有用。我们讨论适合人群,这类东西不适合中高级程序员



说那么多,你得学会判断这个人是不是大佬




你都可以简历包装,为什么‘大佬’就不会是被包装的



那就稍微整理一下,哪些是真大佬,伪大佬


真伪大佬


某佬博客开源项目学习人群是否顺眼
伪大佬面试题居多,很多基础内容,没有干货无,或者很少。动不动就是商城,博客应届生占比较多可能顺眼
真大佬博客、论坛内容干货。整理分类完善,你能学到东西有,某些大项目的贡献,同时也有优秀开源项目应届生,中高级都有大多数不顺眼,因为实在优秀

就学习人群做一个说明



  • 在就业容易程度上,相对于初中高级别的程序员,应届生无论从考察的内容,招聘的人数。都会容易丢丢。

  • 他说跟着他学,offer赢麻了。但是其中,找到工作的大多数都是应届生


就这些点,我们其实可以能判断个大概了。


记住,你想知识付费。一定要摸清他的底细,不能认为他说得都是对的。人家也是会包装的


你的hello world


或许每个程序员的第一行代码,都是


    print("hello world")

我想说的是,请你记住你的初心。



  • 转行过来当程序员,就是为了狠狠赚他一笔

  • 喜欢写代码,苦中作乐


情况每个人都不太一样,这里不细说。明白你是谁,你还是否有动力能坚持下去。明白这一点,远比你在迷茫的时候病急乱投医更为重要,请勿过度焦虑


为此,后面会说一下如何学习,以及找工作如何不被骗


力量大会


事关钱包的问题,我们都得谨慎谨慎。就业市场那恶劣,朋友找不到工作还被坑了一把。骗子实在可恶。请你先自身强大,先自己找出问题,不花冤枉钱,避免传销式编程


如有雷同,纯属巧合,没有针对任何人,也没有动某些人的饭碗。


作者:Goland猫
来源:juejin.cn/post/7357231056288055336
收起阅读 »

勇敢的人先拿到结果

上周许久未见的大学学长叫我出去喝酒,他这次来贵阳是为开分店的事情而来的,他比我高一个年级,在我毕业的时候,他就自己开始做生意了,短短两三年,到现在他已经开了七八个分店了,还在不断发展,并且加盟的人也不少,平均下来,现在每个月的收入也是很可观的。 对于我们这种末...
继续阅读 »

上周许久未见的大学学长叫我出去喝酒,他这次来贵阳是为开分店的事情而来的,他比我高一个年级,在我毕业的时候,他就自己开始做生意了,短短两三年,到现在他已经开了七八个分店了,还在不断发展,并且加盟的人也不少,平均下来,现在每个月的收入也是很可观的。


对于我们这种末流二本院校毕业的学生,特别还是在贵州这个经济相对比较落后的地区,拿到这个成绩还是挺厉害的,并且这个收入并不是固定的,还是不断增长。


学长是学市场营销的,这也算是个天坑专业,所以那会他就知道自己将来肯定是从事不了这个行业的,所以自己就在宿舍开了一个小卖部,每天下课后就骑着电瓶车去送货,虽然每个月赚不了多少钱,但是对于做生意这一块,他的思维肯定是得到了锻炼。


因为我们是在广西读书,所以螺蛳粉就比较多,在毕业后,他就去柳州考察做螺蛳粉,联系好各种渠道后,回到贵州就直接开干。


因为那会贵州的各个市里面卖螺蛳粉的还很少,并且没有特色和品牌效应,所以自己就先设计名称,logo,最后先开了一个店铺,自己亲自下厨,因为比较有特色,一个月直接干到了全市螺蛳粉餐饮销量的第二名。


随后又开了第二家,第三家......别人在看到他赚了钱后,其它市区的人也纷纷向他学习,他自己就收加盟费用,现在他要做的事情就是玩,还有考察门店,然后扩展。


从他的事迹中,我说两个点。


勇于放弃


对于很多人而言,读书的目的就是为了找一份稳定的工作,最好是体制内。


如果你读完大学后出去做销售,做生意,那么对于你身边的很多人而言,他们会觉得你这个大学白读了,因为在他们眼中,只有坐在办公室里面才是最体面了。


你和他说做生意,创业这些东西,他会给你说:这些不稳,以后没有退休工资。


但是如果你真听他们的,那么后面后悔的一定是你。


就像学长,如果他也和别人一样毕业后回到自己那地方加入考编大军,那么他现在肯定和别人一样,也在背书,焦虑,但是他选择了其它的路。


这时候有些人就会抬杠:考上了就能吃一辈子,而你做生意如果运气不好那么就直接亏光,到时候你就知道编制的香了。


这也是很多人的通病。


我觉得如果一件事情你看不到希望,就别过于去迷恋它,舍不得它,不然会被它束缚,比如学历,经验等等。


敢想敢干


可能你会觉得他家里应该有底子的,不然毕业后怎么就能开店。


但是我们问一下自己,就算你家里有底子,毕业后就给你十万块让你开店,你觉得你行吗?恐怕大部分人都不知道自己该做什么吧。


首先躬身入局本身就是一件很难的事情,我们多数人能够拼命上班,但是如果让你脱离平台去自己干一件事就比登天还难。


因为你在公司有别人给你安排好,你去做就行了,换句话来说,你就是个干苦力的,真让你去谈判,去闯市场,大多数人是没这个能力的。


这也是一种损失厌恶心态,因为你怕自己花时间去做,到后面不仅亏了钱,还把自己弄得很累,而安安稳稳打工不一样,它是“稳赚不赔”的。


但是这个世界上很难有稳赚不赔的东西,就说安安稳稳打工拿工资,但是工资不高,那一定是在亏着走的,除非你觉得自己的时间毫无价值,那么就是赚的。


作者:苏格拉的底牌
来源:juejin.cn/post/7340898858556178432
收起阅读 »

感觉根本等不到35岁AI就把我裁了

感觉等不到35岁AI就把我裁了哥们干前端,刚过34周岁生日,请有缘的老哥兄弟们在评论区里祝哥们生日快乐先。让我焦虑的不是年纪,是这个叫Windsurf Editor的东西之前用过他们家的AI工具,感觉和市面上卷的AI工具相差无几。但自从Cursor出了个编辑器...
继续阅读 »

感觉等不到35岁AI就把我裁了

哥们干前端,刚过34周岁生日,请有缘的老哥兄弟们在评论区里祝哥们生日快乐先。

image.png

让我焦虑的不是年纪,是这个叫Windsurf Editor的东西

之前用过他们家的AI工具,感觉和市面上卷的AI工具相差无几。但自从Cursor出了个编辑器想要取代vs code,这事儿就逐渐不对劲了。

Codeium他们家也出了个编辑器叫Windsurf Editor,今天体验了一下,突然开始焦虑了。体验下来就一个感受:我想过这一天会来,没想到来的这么快

事情是这样的,我让AI帮我创建了一个前端项目,其中要用到xxx技术。然后全程我除了accept它给我生成的指令,我没有敲一行代码。

我自己不喜欢读长篇文字,所以直接看图吧。

image.png

image.png

可以看出它已经具备分析整个项目和整合项目代码的能力。

然后我让它帮我封装了一个RESTFUL式的基于axios的单例请求文件。结果我发现它在request文件中用到了状态管理中的数据(pinia)以及UI组件(ElementPlus),于是让它帮我修改。

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

最后还不忘给个使用示例

image.png

结语:这是一场程序员和技术的自我革新,不仅是我们这个领域,新的时代真的来临,大家一起努力吧,共勉之。


作者:fhf
来源:juejin.cn/post/7441543396979097610

收起阅读 »

马斯克招人策略曝光:9 轮面试,底薪低于同行,只招 “铁杆特斯拉人”

事情是这样的。 Business Insider 最近获得了特斯拉内部薪酬数据库(截至 2021 年 12 月)的访问权限,里面有 10 万名员工的薪酬数据。 然后他们发现了有关特斯拉薪酬的一系列猛料: 面试 9 轮只为招聘特斯拉铁粉; 采用低底薪 + 股票...
继续阅读 »

事情是这样的。


Business Insider 最近获得了特斯拉内部薪酬数据库(截至 2021 年 12 月)的访问权限,里面有 10 万名员工的薪酬数据。


然后他们发现了有关特斯拉薪酬的一系列猛料



  • 面试 9 轮只为招聘特斯拉铁粉;

  • 采用低底薪 + 股票奖励策略,打出 “高风险、高回报” 口号;

  • 特斯拉底薪低于同行,不及苹果、谷歌、英伟达、Meta、福特等科技公司和传统汽车制造商;

  • 工程师更有可能获得股票奖励;

  • 仅有 4% 的员工通过激励股票期权(ISOs) 获得股票,且通常授予高管;

  • ……



更多爆料细节如下——


马斯克招人策略:低底薪 + 股票奖励


透过这份曝光的内部薪酬文件,我们看到特斯拉向员工喊出的是 “高风险、高回报” 这一口号。


why??


一切的一切,还是归于特斯拉想要招聘自身铁粉。据一位了解招聘的内部员工透露:



他们可能在别处得到更好的报酬,但我们想要的是铁杆的特斯拉人。



而为了实现这一目标,特斯拉主要靠 “低底薪 + 股票奖励” 这一策略以及配套的招聘系统


对于前者,一位特斯拉前销售经理将其比喻为 “金手铐”:



股票是主要的钩子…… 我要低下头再等几个月,直到我获得股权。



至于后者,一位特斯拉前招聘人员表示,前司的招聘流程极为严格,通常需要几个月时间来考察面试候选人。


比如面试一位工程师,通常至少包括九次面试,可能需要数月时间



这是一件文化上的事情,一切都是为了排除掉只想 “打卡上下班” 的员工。




那么,特斯拉到底给员工们开了多少薪酬呢?


这里需要补充一个员工人数数据。在这份文件里,我们可以看到 10 万名员工的薪酬情况,而据 CNBC 报道,截至今年 6 月,特斯拉雇佣了大约 12 万名员工(包括正式员工和临时工)。


下面具体来看。


第一,先从公司内部来看。


首先,Business Insider 分析了大约 13,000 名全职、有薪、美国本土员工的平均基本工资(年薪),这些员工分属特斯拉的各个业务部门(如工程、制造或数据管理),而且排除了无法准确计算平均年薪的小时工。



可以看出,这些员工的基本工资中位数(年薪)大多在 10 万美元和 15 万美元之间。


接下来,Business Insider 进一步将数据细分,并查看特斯拉管理岗(全职、美国本土员工、有薪且手下至少有五名员工)的基本工资情况。


结果显示,包括工程总监和在特斯拉服务中心维修车辆的经理在内,这些人的基本工资中位数(年薪)从大约 35,000 美元到 324,000 美元不等。



而且据 9 位现任和前员工透露,自 2021 年 12 月以来,特斯拉的薪酬结构基本保持不变


换句话说,虽然上述数据看起来老旧,但特斯拉目前仍在延续这些薪酬方案。


不过,只看内部情况,我们可能无法直观感受特斯拉的 “低底薪”。


别急,Business Insider 还另外使用了来自证券交易委员会的数据,将特斯拉的基本工资与传统汽车制造商以及市值最大的六家科技公司进行了比较。


可以看出,除了亚马逊,特斯拉均处于落后地位。


而且我们知道,像亚马逊和苹果这样的公司,它们还拥有庞大的仓库劳动力和零售劳动力,这些因素也会影响公司的平均工资。


因此,一个基本情况浮出水面:



特斯拉的基本工资通常低于竞争对手




那么,接下来的问题是:员工为什么愿意接受低底薪呢?


最大原因还是在于股票


9 位现任和前工程师及销售人员表示,特斯拉的股票授予计划使得他们更容易接受较低的底薪。


据悉,过去 5 年,特斯拉的股价飙升超过 1000%;而今年,虽然特斯拉股价经历了显著波动(4 月中旬跌至年初价格的 44%),但在川普成功竞选后,特斯拉收获重大利好,其股价至今累计上涨近 30%。


so,又有多少员工能享受到特斯拉的股票奖励呢?


据内部文件显示,2020 年和 2021 年,有 44 名美国本土员工获得了价值超过 100 万美元的股票。


为了了解哪些员工更有可能获得股票奖励,Business Insider 根据职位类别对股票奖励进行了拆分。


结果显示,大多数工程师收到的股票奖励超过 25,000 美元。(股票的价值基于授予时的股价,但会根据特斯拉的股价变动而变化)



不过需要注意的是,特斯拉将限制性股票单位(RSUs)作为薪酬结构中的主要组成部分,约占薪资发放的 75%。


解释一下,RSUs 指授予时并不立即转化为实际的股票,而是在一定时间锁定期后,以公司股票的形式提供给员工。


换句话说,员工在满足特定条件(如服务年限或公司业绩目标)后才能获得 RSUs 股票。


同时,特斯拉将非合格股票期权(NQSOs) 作为基于业绩的薪酬的一部分,占薪资发放的 21%。


最终,仅有 4% 的员工通过激励股票期权(ISOs) 获得股票,且通常授予高管和其他高级员工。


而对于这一部分,内部文件显示,特斯拉高管中,除一名未列出持股数量的员工外,其余人收到的股票价值在 95 万美元至 2000 万美元之间。



除了股票,另一大原因在于特斯拉的公司形象


按照招聘公司 Stanton Chase 一位总监的说法:



它包含一个以使命为导向的元素…… 这些人正在努力实现地球的脱碳。



更不必说,还有 CEO 马斯克这位顶流的卖力宣传(doge):



我们给每个人股票期权,我们让许多只是在工作一线的人——甚至不知道股票是什么的人——变成了百万富翁。



马斯克 560 亿美元天价薪酬案将于年底见分晓


那么,老马本人在特斯拉的薪酬水平如何呢?


事实上,“马斯克 560 亿美元天价薪酬案” 一直引人关注:


2018 年,特斯拉为马斯克制定了一项为期 10 年的激励计划,方案核心是通过股票期权的方式,将马斯克的个人利益与公司的市值和业绩紧密绑定。


简单说,一旦老马能完成 KPI,他将累计获得特斯拉 12% 的股票期权作为奖励,总价值约为 560 亿美元,这一方案也被外媒认为是美国有史以来规模最大的高管薪酬方案。


当然了,当时来看公司定的 KPI 非常难,结果没想到后来特斯拉一路起飞,市值大涨(目前已来到 1.12 万亿美元)。


这下就有股东跳出来,觉得不公平了。


2022 年,特斯拉的部分股东将马斯克告上法庭,称他将大部分精力花在 SpaceX 等其他公司上,同时利用其对公司及董事会的控制敲定了长期薪酬计划,因此希望废除该方案。


紧接着,特拉华州的法官便以 “对股东不公平” 为由,宣布马斯克的长期薪酬方案无效。


面对这一判决,老马一怒之下宣称将特斯拉的注册地从特拉华州迁至得克萨斯州。(后来确实迁了)


并进行了上诉。


而最终结果,将在今年年底前得到裁决。


就在上周四,负责审理此案的特拉华州衡平法院大法官凯瑟琳・麦考密克(Kathaleen McCormick)表示,她将在 2024 年年底前作出最终决定。


不过,尽管之前的法院判决不利于老马,但特斯拉股东在 2024 年 6 月 13 日的年度股东大会上,已经以较大优势批准了这一薪酬方案。



参考链接:

x.com/BusinessIns…



作者:量子位
来源:juejin.cn/post/7436286873523421238
收起阅读 »

百亿补贴为什么用 H5?H5 未来会如何发展?

web
23 年 11 月末,拼多多市值超过了阿里。我想写一篇《百亿补贴为什么用 H5》,没有动笔;24 年新年,我想写一篇《新的一年,H5 会如何发展》,也没有动笔。 眼看着灵感烂在手里,我决定把两篇文章合为一篇,与你分享。提前说明,我并非百亿补贴的开发人员,本文的...
继续阅读 »

23 年 11 月末,拼多多市值超过了阿里。我想写一篇《百亿补贴为什么用 H5》,没有动笔;24 年新年,我想写一篇《新的一年,H5 会如何发展》,也没有动笔。


眼看着灵感烂在手里,我决定把两篇文章合为一篇,与你分享。提前说明,我并非百亿补贴的开发人员,本文的内容是我的推理。


拳打 H5,脚踢小程序。我是「小霖家的混江龙」,关注我,带你了解更多实用的 H5、小程序武学。


我的证据


在 Android 开发者模式下,开启显示布局边界,你可以看到「百亿补贴」是一个完整大框,这说明「百亿补贴」在 App 内是 H5。拷贝分享链接,在浏览器打开,可以看到资源中有 React,说明「百亿补贴」技术栈是 React。


pdd-stack.png


不只是拼多多,利用同样的方法,你可以发现京东、淘宝的「百亿补贴」技术栈也是 H5。


pdd-jd-taobao.png


那么,为什么电商巨头会选择做「百亿补贴」时会选择 H5 呢?


我的推理逻辑


解答问题前,我先说明下推理逻辑。巨头可能选择 H5 的原因千千万万,但最有说服力的原因,肯定具有排他性


什么是排他性?


举个例子,成功人物为什么成功,如果我回答「成功人士会喝水」,你肯定不满意。如果我回答「成功人士坚持不懈」,你会更满意一些。喝水分明是成功人士成功的原因,不喝水人会渴死,没办法成功。你为什么对这个答案不满意呢?


因为「喝水」不具备排他性,普通人也会喝水;而「坚持不懈」比「喝水」更具排他性,大部分普通人没有这个特质。


按照排他性,我需要说明百亿补贴只有 H5 能干,其他技术栈不能干,这样才有说服力。


百亿补贴为什么用 H5?


现在进入正题。粗略来看,大前端的技术栈分为 Native 和跨平台两大类。前者包括 3 小类,分别是 Android、iOS、纯血鸿蒙;后者也包括 3 小类,分别是基于 Web 的方案、基于系统 UI 框架的方案(比如 React Native)、自己绘制 UI 的方案(比如 Flutter)。


其中,基于 Web 的方案,又可以细分为纯 H5 和 DSL 转 H5(比如 Taro)。


graph TB;
大前端 --> Native;
Native --> Android;
Native --> iOS;
Native --> 纯血鸿蒙;
大前端 --> 跨平台;
跨平台 --> 基于Web的方案;
跨平台 --> 基于系统UI框架的方案;
跨平台 --> 自己绘制UI的方案;
基于Web的方案 --> H5;
基于Web的方案 --> DSL转H5;

我们需要排除 H5 外的其他方案。


原因一:百亿补贴迭代频繁


百亿补贴的业务形式,是一个常住 H5,搭配上多个流动 H5。(「常住」和「流动」是我借鉴「常住人口」和「流动人口」造的词)



  • 常住 H5 链接保持不变,方便用户二次访问。

  • 流动 H5 链接位于常住 H5 的不同位置,方便分发用户流量。


具体到拼多多,它至少有 3 个流量的分发点,可点击的头图、列表上方的活动模块和侧边栏,3 者可以投放不同链接。下图分别投放了 3.8 女神节链接、新人链接和品牌链接:


pdd-activity.png


可以想到,几乎每到一个节日、每换一个品牌,「百亿补贴」就需要更新一次。


这样频繁的迭代,框架必须满足快速开发、快速部署、一次开发多端复用条件。因此可以排除掉 Native 技术栈,留下动态化技术栈。


原因二:百亿补贴需要投放小程序和其他 App


如图所示,你可以在微信上搜索拼多多,可以看到百亿补贴不仅在 App 上投放,还在微信小程序里投放。


pdd-wx.png


此时我们几乎可以排除掉 React Native 和 Flutter 技术栈。因为社区虽然有方案让 React Native、Flutter 适配小程序,但并不成熟,不适合用到生产项目中。


此外,如果你在抖音、B 站和小红书搜索百亿补贴,你可以看到百亿补贴在这些 App 上都有投放广告。


pdd-advertisement.png


这点可以完全排除 React Native 和 Flutter 技术栈。据我所知,目前没有主流 App,会愿意让第三方在自己的 App 里运行 React Native 和 Flutter。


原因三:百亿补贴核心流量在 APP


现在只剩下了基于 Web 的 2 种技术方案,也就是 H5 和 DSL 转出来的 H5(比如 Taro)。


百亿补贴的 HTML 结果,更符合原生 H5 的组织结构,而不是 Taro 这种 DSL 转出来的结构。


我对此的解释是,百亿补贴的核心流量在 App。核心流量在 APP 时。投放小程序是锦上添花,把 H5 嵌入到小程序 Webview 就能满足要求,不需要卷性能。


如果百亿补贴的核心流量在小程序,那么大概率就会使用 DSL 框架,转出来小程序代码和 H5 代码。


综上所述,迭代频繁、需要投放小程序和其他 App,核心流量在 App,是百亿补贴选择 H5 的 3 个主要原因。


H5 未来会如何发展


知道百亿补贴选择 H5 的 3 个原因后,我们可以得到结论,如果 3 个前提不变,未来很长一段时间内,H5 依然是电商活动的主流方案。


不过,主流方案并不意味着一成不变,我认为未来 H5 会有 2 个发展趋势:


趋势一:离线包、SSR 比例增加


H5 有诸多优势的同时,也有着先天缺陷,那就是下载成功率低、容易白屏。


解决这个问题,社区主流的两个方案是离线包和 SSR。


离线包可以将网页的静态资源(如 HTML、CSS、JS、图片等)缓存到本地,用户访问 H5 页面时,可以直接读取本地的离线资源,从而提升页面的加载速度。阿里云腾讯云等云服务商都有自己的离线包方案。


SSR 即服务器端渲染,它可以减少白屏时间,让用户更快看到页面。传统的 CSR(客户端渲染)初始时只渲染空白的 HTML 框架,然后再去获取数据并渲染内容。而在 SSR 中,服务器在接收到客户端请求时,会在服务器端利用数据和模板生成完整的 HTML 页面,再把页面发送给客户端浏览器。


不难想到,业务陷入瓶颈后,企业开始看中性能,大部分前端开发者都会来卷一卷离线包、 SSR,它们的比例会进一步增加。


趋势二:定制化要求苛刻


近年 C 端市场增长缓慢,企业重点从扩张新客,变成留存老客。


这个背景下,定制化要求变得越来越苛刻,目的是让用户区分各种活动。用互联网黑话来说,就是「建立用户心智」。


下面是拼多多、京东、淘宝、12306、中国移动和招商银行的活动 H5,尽管它们结构都差不多,但长得是千奇百怪。


fluid.png


12306-yidong-zhaoshang.png


我估计未来,电商活动 H5 的外观将变得极具个性,各位前端同学可以在卷卷 CSS、动效方向。


总结


本文介绍了我认为「百亿补贴」会选用 H5 的 3 大原因:



  • 百亿补贴迭代频繁

  • 百亿补贴需要投放小程序、其他 App

  • 百亿补贴核心流量是自己的 App


以及我 H5 未来发展趋势的 2 个预测:



  • 离线包、SSR 比例增加

  • 定制化要求苛刻


拳打 H5,脚踢小程序。我是「小霖家的混江龙」,关注我,带你了解更多实用的 H5、小程序武学。


作者:小霖家的混江龙
来源:juejin.cn/post/7344325496983732250
收起阅读 »

2024年总结: 迷茫

12月今年最后一个月了,相逢的人已走散, Q4的OKR已经定型了, 很平淡无味, 闲的无聊 提前写个年终总结吧。00年, 再过一个月就25岁了,一个人来杭州也已经3年多了 每天有时间写一点 周六了 写到凌晨1点了 看直播/打麻将到凌晨5点才睡。 去年也写了一篇...
继续阅读 »

12月今年最后一个月了,相逢的人已走散, Q4的OKR已经定型了, 很平淡无味, 闲的无聊 提前写个年终总结吧。00年, 再过一个月就25岁了,一个人来杭州也已经3年多了 每天有时间写一点 周六了 写到凌晨1点了 看直播/打麻将到凌晨5点才睡。 去年也写了一篇 2023年总结:日渐清醒,得失随意 //TODO DDL 应该是在月中完结吧。



工作



我大概回忆一下 我今年在工作上应该干了这些事情吧




  • 自己申请换项目组,日常维护新品App版本迭代 2周一个版本 多个app同时进行

  • 完成所有App 苹果服务器接口Storekit2 升级上线

  • Google 支付/订阅 SDK 重构原生API调用代码

  • RocketMQ优化多数据中心用户数据同步/webhook/推送

  • RocketMQ-Exporter 搭建 监控相关性能指标

  • SSE+服务器GRPC流式 推送消息

  • us机器 内存优化 切换到jemalloc内存分配器

  • RocketMQ 单机 升级为Dledger 集群模式 Q4 任务



从22年3月毕业到现在 再度过一个季度 在这家公司呆三年了(3年之约),整个过程就是升级打怪,看着人来人往 合作的人 离职一个又来一个, 每个季度干着重复的工作,技术框架还是那一套 SpringBoot+GRPC 经过一年熟悉后 就觉得没有新鲜感了, C端产品App 在用户基数不大情况下 基本的重心在客户端的ui/操作体验上 后端嘛就是一个数据存储的地方 存取能有什么难度 大家都会,每个季度任务就是 基本的版本迭代+一些服务器内部的优化,如果你想要拿到高的绩效 那干这点是远远不够的, 基本规则在无告警的版本迭代下 做一些对团队贡献大 有价值的事情 拿A/季度优秀员工,三年期间升了两次小级别 p5-1->p5-2->p5-3 还是一个初级开发 今年估计也悬了 没有两次A的绩效 跨段位升没机会,没有owner过项目, 和旁边人朋友/同学工作/升职对比下 只能说自己像个废物 躺的太平了 每天965的生活 除了偶尔上线 需要加班留下来 大家都不加班 也没有那么多活需要加班来干的活。




生活



去年立的flag 也是一腔鸡血




  • 软考 系统架构师 +软著 拿到杭州E类人才

  • 健身/减肥

  • 骑车 vlog (杭州景点全部骑完 影石360 ace pro)

  • 摄影佳能rp/视频剪辑学习

  • 日语/英语学习

  • leetcode 上Knight

  • 考D驾-照 骑防赛

  • 日麻线下雀庄体验 参加各种线上日麻比赛

  • ClickHouse hangzhou 线下沙龙

  • 掘金bolg 更新 技术日常

  • 千岛湖

  • 抽烟+喝酒

  • B站 直播 日麻


软考 系统架构师+软著 拿到杭州E类人才



img


骑车 vlog (杭州景点全部骑完 影石360 ace pro)



  • 一个人走走停停 骑过很多地方, 最多的还是钱塘江到彭浦大桥->复兴大桥路线 不知道骑了多少遍,西湖/湘湖/九溪这些地方都去过了,车子是青春款只在线上售卖 后期毛病很多 链条蹭盘/刹车无效 自己不知道维修了多少次,最近这两个月很少骑了,放在地下室发霉 后续准备卖掉了这车 还买了那么多骑行装备,买的insta 360 ace pro 3000多降价到2k左右 当时在大疆和insta中选择了好久 最后还是踩坑了 实体店体验了大疆action 画质比insta360好太多了,有必要考虑再买一台大疆action5了, 一个人的骑行之路也该结束了 开始新的玩具 仿赛摩托车 芜湖起飞。


img
img
img
img
image.png

健身/减肥



  • 怎么说呢 三天打鱼两天晒网的行动 体脂没什么变化,饮食更不会控制 每天外卖外卖外卖, Q1/Q2两个季度挺积极的 基本工作日晚上有时间就去健身房 周末白天也去, 在健身房的时间也能让自身感受到轻松, 这个小区有个百姓健身房在地下室 24小时 刷脸进去 设备齐全 没什么人 每个季度的话300块RMB, 我主要后面可能没有看到短期效果+活着很累 有一段时间没有去了, 偶尔下楼抽烟去逛逛, 最后得到的只是自己的一个心里安慰,没有合理的计划和坚持下去的心 我现在已经懒连手表都不戴了。


img
img
img
img

摄影佳能rp/视频剪辑学习



  • 怎么说呢 周末放假就是宅 已经吃灰了 除了9月1号 拿到免费的门票 杭州植物园专门去了一趟拍彼岸花,其他时间不出手。视频剪辑也是一坨屎 目前就用剪映弄一些雀魂麻将抽角色的视频,后续还是想学一下专业的剪辑工具 这个也看需求吧。


img

考D驾-照 骑防赛



  • 为什么要去骑摩托车,主要是中秋节回家一趟,隔壁邻居已经买了一辆机车, 当时他让我试试 我没试 后面就一直关注摩托车这个事 抖音一直给我推视频。才有了考D驾-照驾-照,周末练半天,工作日考试半天就好了,4科联考 比C1驾-照周期短 速度快,驾-照到手后面周末直接找附近最近的租车平台试试水,萧山那边的之江路/美女坝路险,本田500 手震麻了 1个小时 干了100公里, 最后一个半小时就还车了 跑了150km,整体的体验感是非常好的,无论是去骑车的路上 还是过程中 都能够忘记生活/工作上的烦心事,最尴尬的是红绿灯起步熄火了,后续周末继续出行租车,找个有缘人一起。


img
img
img

日麻线上比赛/线下雀庄体验



  • 每天下班就是点外卖 开始打麻将,水各种日麻群 打友人赛/团队赛,每天晚上达到2 3点 菜就爱多玩 和群友打比赛 对个人的实力也是有了认知 学习别人的打法 从野猪冲击 也慢慢在意铳率了,前一天打完线上比赛, 这个月周日也是马上跟着一个大哥去杭州线下的湖滨牌浪屋体验完线下日麻,今年干的最多的事情就是打麻将,下班除了打麻将还是打麻将。


img
img
img
img

leetcode 上Knight



  • 基本上是原地没动,比赛一场没打,为什么要刷?为了什么?能带给自己什么收益?呆在舒适圈里久了 不想出去,算法也是提不上一点兴趣了 估计只有到时候找工作之前才会接触到了 其实也制定了计划 刷灵神的清单 还是自己懒吧 动不起来,最后一个月 要不开始发力?算了 打麻将吧。


img

其他



  • 今年参加了ClickHouse hangzhou 线下沙龙, 虽然没有使用过clickhouse这款db,去听听别人公司的落地方案,去阿里园区转了转。

  • 掘金bolg 更新 技术日常 主要是参加创作者训练营吧 锻炼一点自己的文本输出能力,总结的过程中也能知道问题的本质是什么,解决的过程/方式以及别人是怎么解决的,收获还是有的。

  • 和同学五一去了千岛湖一趟 结局不是很好 过程体验不错。

  • 在日语/英语学习上面投入的时间 ,无论是日常工作上英语的使用 还是各种文档阅读能力,在逛各种项目/看论文的时候 就能体现出来, 日语兴趣的话 纯粹是打日麻和旁边的日麻群友影响/看番剧而来的 每天用多邻国完成任务,买了4本书《标准日语》+《大家的日语》,在B站上看圆圆姐的视频教程【京大博士带你学日语】新标日初级上册全新课程!必能学会!超详细讲解!轻松搞定日语学习!(课本内容完结!)哔哩哔哩bilibili

  • 抽烟+喝酒已经是家常便饭一样的事情了 上半年是沉迷于喝酒消愁 下半年就抽烟打发时间,每天下班又不知道干什么 找点打发时间的乐趣,天天熬夜看直播 打麻将 2点3点睡觉已经是常态了,每天晚上看陈伯/刘刘江直播 带来的乐趣, 工作日每天基本8点50的闹钟吵醒,拖着尸体去上班,周末基本睡到自然醒中午/下午 除了楼上楼下装修 直接被震醒了。

  • 这样一回想2024年还是干了很多无意义的事。



虽然只有15篇文章 文章的阅读数也有3w 其实数据对我来说也是无所谓的,主要还是方便以后回忆吧,分享出去 可能有人和你遇到相同问题,带给解决思路 明年要不要继续写?还是把时间投入在别的地方?都是未知



img
img
img

个人技术学习



  • AI 知识点拓展学习

  • 部门分享

  • 推荐系统&&RAG

  • 前端

  • 第三方支付订阅

  • 分布式论文学习总结

  • 《计算机网络-自顶向下方法第七版》

  • 《CSAPP 深入理解计算机系统(第3版)》

  • 《设计数据密集型应用》

  • 技术拓展/深挖(RocketMq源码/go-redis源码/Netty源码/Mycat2源码)



看个锤子 没心思学习 下半年天天打麻将




  • AI的话主要是身边环境影响,自己的项目组一直在利用AI做业务,从2023年开始 公司一直对接的是openai 提供的chat 能力,公司内部举行了ai相关的比赛,业务想要搭建自己的知识库和RAG搜索 主要是用AWS上的Redrock封装好的知识库 ,项目组一些APP一直在使用微软的TTS进行语言转音频的操作,部门,组内和项目组 大家一直在内部分享和ai相关的知识点,产品会使用cursor提前将需求写完 自己进部署上线。

  • 跟着项目组业务走,最近在支付方面的功能进行了改动,对于web网页上的购买消耗型商品/续费型商品的购买,主要对接的平台是Stripe信用卡visa支付 和paypal支付。appstore 支付的话 最近负责组内storekit2 服务器接口升级重构代码 用的官方开源库 github.com/apple/app-s…。Alipay 支付宝和Wechat 对于中国环境的用户提供的一种支付方式, 代码很粗糙 很久没有相关需求迭代了。Google 支付 来的两年时间接触的业务还是比较少,整个支付逻辑和appstore是一致的,有时间把代码逻辑和官方文档进行学习总结一下。

  • 现在只会个后端远远不够了,替代性太强了,除非是中大厂那样细分工作岗位/业务内容,如果你有自己的想法 后续做一些自己的产品/独立开发者 一人一公司 全栈只能是无敌路。我这边对前端也是零零散散的学习 没有整个的大项目使用,github.com/lobehub/lob… 前端React开源项目学习 TSX+TS 认知冲击 原来前端已经进化到这个地步了,没有html+css全部被封装了,我们内部的数据平台还是原生html+django搭建的,每次加新功能ai生成的代码 能跑就行。



在下半年 觉得基础知识很重要 技术跟着业务走 没必要太追求新技术 就往计算机基础知识+算法+基础论文投入时间




  • 中间一段也是将《计算机网络-自顶向下方法第七版》 计算机网络-自顶向下方法第七版 · 语雀和《CSAPP 深入理解计算机系统(第3版)》CSAPP 深入理解计算机系统(第3版) · 语雀 细看了一遍 , 书籍买了很多 都是吃灰的 没有去年那个干劲了。

  • 看论文 可以学习技术理论的基础 还有重要一点是学英语, 主要是看一个up在学习这方面的知识点 就跟着看了一段时间,谷歌三大剑客 GFS/MapReduce/BigTable 看论文不看分布式论文 就像四大名著不读红楼梦,唐诗不读李杜,吃泡面不加调料包 Raft/Paxos 那一块真的一看就是几天 深陷进去 每次看硬核课堂的文章 Raft -论文导读 与 ETCD源码解读

  • 参与开源项目任务也没有达成 往里面投入的时间太少了,最后下班/上班有时间 也没深入去学习业务上用到的组件源码, 最近的话 负责RocketMQ集群Dledger搭建/MQ优化业务 ,RocketMQ-exporter+herzbeat+prometheus监控指标, 遇到的异常信息太多 每次都是网上找案例解决,上班利用ai 深入在看看RocketMQ源码吧github.com/apache/rock… 边看边总结RocketMQ 源码 5.2.0 - 生产者 Producer



杂学杂记




  • 中间又去了解了下机器学习/深度学习相关的内容,又看了大数据开发Spark/Flink等等组件,前端看了React+TS相关知识点/demo/Flutter开源项目, 背单词的时候发现墨墨背单词是node+ts写的,有个软考刷题的app是Flutter写的 作者是独立开发者 最近公司客户端也在用flutter开发新品app 代码我这边也是有权限的, 也去了解了一下技术栈,中间又有一段时间去了解了下亚马逊运营的工作,也看了AIGC/agent/图像/音频/向量数据库milvus等相关的方向 RAG 知识库增强式搜索,在推荐系统领域 推荐 广告 搜索 也花了一段时间去了解/学习 因为我们这边没有算法工程师 推荐功能很粗糙 没有用户画像的概念,有一段时间被cloudwego社区的kitex/hertz吸引 当时想去上海站的线下沙龙 可惜正好那周软考考试, 因为有个麻将牌谱工具是rust写的 github.com/Equim-chan/… 所以又去了解了一下rust,我记得有段时间投入在系统设计/业务场景思考方向(IM/Feed流/本地消息表/分布式限流等等), 都是一点毛皮,Q2服务器服务的内存问题 每天上班想下班想 把互联网的文章都翻烂了 从堆内到堆外到Glibc 询问各种技术大佬场景异常 组内成员给不了你任何帮助 全靠自己,所有的东西没有实质性的收获 也没有在项目中使用到 过了一段时间基本全忘了(不做笔记/总结) 。



现在往回看 在技术学习的时长投入的太少了 对技术没有追求 什么都知道一点 什么都不精通 啥也没学会 离开了Java/Spring 我还能干什么,我能干的 找个会使用AI的人来都能干,天天熬夜 不知道熬的是什么 碌碌无为。最近一年 代码写的很少了 基本靠ai生成 微改/设计一下 写的自己也看不懂了。生活/工作迷茫 现在都是活一天是一天, 想回家。



后续规划 待定



  • 英语/日语

  • 独立开发者



打麻将去咯 一起玩雀魂的可以加我



20241212-151216.png

作者:呆呆蛇
来源:juejin.cn/post/7445511025702764555
收起阅读 »

pnpm 的崛起:如何降维打击 npm 和 yarn🫡

web
今天研究了一下 pnpm 的机制,发现它确实很强大,甚至可以说对 yarn 和 npm 形成了降维打击 我们从包管理工具的发展历史,一起看下到底好在哪里? npm2 在 npm 3.0 版本之前,项目的 node_modules 会呈现出嵌套结构,也就是说,我...
继续阅读 »

今天研究了一下 pnpm 的机制,发现它确实很强大,甚至可以说对 yarnnpm 形成了降维打击


我们从包管理工具的发展历史,一起看下到底好在哪里?


npm2


在 npm 3.0 版本之前,项目的 node_modules 会呈现出嵌套结构,也就是说,我安装的依赖、依赖的依赖、依赖的依赖的依赖...,都是递归嵌套的


node_modules
├─ express
│ ├─ index.js
│ ├─ package.json
│ └─ node_modules
│ ├─ accepts
│ │ ├─ index.js
│ │ ├─ package.json
│ │ └─ node_modules
│ │ ├─ mime-types
| | | └─ node_modules
| | | └─ mime-db
| │ └─ negotiator
│ ├─ array-flatten
│ ├─ ...
│ └─ ...
└─ A
├─ index.js
├─ package.json
└─ node_modules
└─ accepts
├─ index.js
├─ package.json
└─ node_modules
├─ mime-types
| └─ node_modules
| └─ mime-db
└─ negotiator

设计缺陷


这种嵌套依赖树的设计确实存在几个严重的问题



  1. 路径过长问题: 由于包的嵌套结构 , node_modules 的目录结构可能会变得非常深,甚至可能会超出系统路径长度上限 ,毕竟 windows 系统的文件路径默认最多支持 256 个字符

  2. 磁盘空间浪费: 多个包之间难免会有公共的依赖,公共依赖会被多次安装在不同的包目录下,导致磁盘空间被大量浪费 。比如上面 express 和 A 都依赖了 accepts,它就被安装了两次

  3. 安装速度慢:由于依赖包之间的嵌套结构,npm 在安装包时需要多次处理和下载相同的包,导致安装速度变慢,尤其是在依赖关系复杂的项目中


当时 npm 还没解决这些问题, 社区便推出了新的解决方案 ,就是 yarn。 它引入了一种新的依赖管理方式——扁平化依赖。


看到 yarn 的成功,npm 在 3.0 版本中也引入了类似的扁平化依赖结构


yarn


yarn 的主要改进之一就是通过扁平化依赖结构来解决嵌套依赖树的问题


具体来说铺平,yarn 尽量将所有依赖包安装在项目的顶层 node_modules 目录下,而不是嵌套在各自的 node_modules 目录中。


这样一来,减少了目录的深度,避免了路径过长的问题 ,也尽可能避免了依赖被多次重复安装的问题


|350


我们可以在 yarn-example 看到整个目录,全部铺平在了顶层 node_modules 目录下,展开下面的包大部分是没有二层 node_modules


然而,有些依赖包还是会在自己的目录下有一个 node_modules 文件夹,出现嵌套的情况,例如 yarn-example 下的http-errors 依赖包就有自己的 node_modules,原因是:


当一个项目的多个依赖包需要同一个库的不同版本时,yarn 只能将一个版本的库提升到顶层 node_modules 目录中。 对于需要这个库其他版本的依赖,yarn 仍然需要在这些依赖包的目录下创建一个嵌套的 node_modules 来存放不同版本的包


比如,包 A 依赖于 lodash@4.0.0,而包 B 依赖于 lodash@3.0.0。由于这两个版本的 lodash 不能合并,yarn 会将 lodash@4.0.0 提升到顶层 node_modules,而 lodash@3.0.0 则被嵌套在包 B 的 node_modules 目录下。


幽灵依赖


虽然 yarn 和 npm 都采用了扁平化的方案来解决依赖嵌套的问题,但这种方案本身也有一些缺陷,其中幽灵依赖是一个主要问题。


幽灵依赖,也就是你明明没有在 package.json 文件中声明的依赖项,但在项目代码里却可以 require 进来
这个也很容易理解,因为依赖的依赖被扁平化安装在顶层 node_modules 中,所以我们能访问到依赖的依赖


但是这样是有隐患的,因为没有显式依赖,未来某个时候这些包可能会因为某些原因消失(例如新版本库不再引用这个包了,然后我们更新了库),就会引发代码运行错误


浪费磁盘空间


而且还有一个问题,就是上面提到的依赖包有多个版本的时候,只会提升一个,那其余版本的包不还是复制了很多次么,依然有浪费磁盘空间的问题


那社区有没有解决这俩问题的思路呢? pnpm 就是其中最成功的一个


pnpm


pnpm 通过全局存储和符号链接机制从根源上解决了依赖重复安装和路径长度问题,同时也避免了扁平化依赖结构带来的幽灵依赖问题
pnpm 的优势概括来说就是“快、准、狠”:



  • 快:安装速度快

  • 准:安装过的依赖会准确复用缓存,甚至包版本升级带来的变化都只 diff,绝不浪费一点空间

  • 狠:直接废掉了幽灵依赖


执行 npm add express,我们可以在 pnpm-example 看到整个目录,由于只安装了 express,那 node_modules 下就只有 express


|400


那么所有的(次级)依赖去哪了呢? binggo,在node_modules/.pnpm/目录下,.pnpm/ 以平铺的形式储存着所有的包


|400


三层寻址



  1. 所有 npm 包都安装在全局目录 ~/.pnpm-store/v3/files 下,同一版本的包仅存储一份内容,甚至不同版本的包也仅存储 diff 内容。

  2. 顶层 node_modules 下有 .pnpm 目录以打平结构管理每个版本包的源码内容,以硬链接方式指向 pnpm-store 中的文件地址。

  3. 每个项目 node_modules 下安装的包以软链接方式将内容指向 node_modules/.pnpm 中的包。
    所以每个包的寻找都要经过三层结构:node_modules/package-a > 软链接 node_modules/.pnpm/package-a@1.0.0/node_modules/package-a > 硬链接 ~/.pnpm-store/v3/files/00/xxxxxx


    这就是 pnpm 的实现原理。官方给了一张原理图,可以搭配食用


    |600


    前面说过,npm 包都被安装在全局 pnpm store ,默认情况下,会创建多个存储(每个驱动器(盘符)一个),并在项目所在盘符的根目录


    所以,同一个盘符下的不同项目,都可以共用同一个全局 pnpm store,绝绝子啊👏,大大节省了磁盘空间,提高了安装速度


    |600



软硬链接


也就是说,所有的依赖都是从全局 store 硬连接到了 node_modules/.pnpm 下,然后之间通过软链接来相互依赖。


那么,这里的软连接、硬链接到底是什么东西?


硬链接是指向磁盘上原始文件所在的同一位置 (直接指向相同的数据块)


软连接可以理解为新建一个文件,它包含一个指向另一个文件或目录的路径 (指向目标路径)



总结


npm2 的嵌套结构: 每个依赖项都会有自己的 node_modules 目录,导致了依赖被重复安装,严重浪费了磁盘空间💣;在依赖层级比较深的项目中,甚至会超出 windows 系统的文件路径长度💣


npm3+ 和 Yarn 的扁平化策略: 尽量将所有依赖包安装在项目的顶层 node_modules 目录下,解决了 npm2 嵌套依赖的问题。但是该方案有一个重大缺陷就是“幽灵依赖”💣;而且依赖包有多个版本时,只会提升一个,那其余版本依然会被重复安装,还是有浪费磁盘空间的问题💣


pnpm全局存储和符号链接机制: 结合软硬链和三层寻址,解决了依赖被重复安装的问题,更加变态的是,同一盘符下的不同项目都可以共用一个全局 pnpm store。节省了磁盘空间,并且根本不存在“幽灵依赖”,安装速度还贼快💪💪💪


作者:柏成
来源:juejin.cn/post/7410923898647461938
收起阅读 »

写点掏心窝子的话

唯有读书和赚钱,才是一个人最好的修行,前者使人不惑,后者使人不屈! 世界上任何一种能力,只要你迫切想学,真心想学,无论身边有没有人教你,你都可以想办法找人,找资源,学会自我学习,自我教育才是最好的教育。 事实上,不管学历怎么样,你一生中绝大部分的东西都是自学的...
继续阅读 »

唯有读书和赚钱,才是一个人最好的修行,前者使人不惑,后者使人不屈!


世界上任何一种能力,只要你迫切想学,真心想学,无论身边有没有人教你,你都可以想办法找人,找资源,学会自我学习,自我教育才是最好的教育。


事实上,不管学历怎么样,你一生中绝大部分的东西都是自学的。


一定要聚焦到自己想做的事情上,并且在头脑里想象自己正在做,而且做得越来越好。


当你的思想,注意力,意识集中在某一个领域,某一件事,某一个行业,某些人身上时,与此相关的大量人,事,物全会被你吸引过来。


对于成年人来说,每个人的时间都是有限的,2025,千万不要再给自己树立太多的目标。


百门通不如一门精,一个人终其一生不如专注一件事,做到极致,朝着一个既定的方向不懈努力的人,几乎都成为社会各界的成功人士。


如果你能只深挖一个点,把事情做到极致,只要肯下功夫,在六个月内你能掌握任何一门学问。


但这不是让你去挑战别人的天赋,深思读书4个月能涨粉10万,只要肯下功夫,你也可以。


因为每门学问所包含的信息量大约是五万个信息块,一个人一分半钟可以记一个信息块。那么五万个大约需要一千小时,以每星期学习40小时计算。


要掌握一门学问,大约需要六个月。


反过来,如果不能专注聚焦于一件事,经不住其他事和人的干扰和诱惑,于是什么都做不精,做不透。


知识是无限的,专业能力有无数种细分领域,行业的经验无穷无尽。


每个都了解一点表面信息,一辈子也不会有成就,每一个专业能力,每一个细分领域赛道,每一个行业都有挖不尽的信息、知识、理论、经验,要用专注和时间去钻研一件事,最容易成为专家有结果的人。


很多人忙碌一生,却不明白真正的优先级是什么!


余认为:


家庭的核心是经济,而不是感情。


职场的准则是价值,而不是努力。


社交的关键是利益互换,而不是单纯的友谊。


教育的目的是培养能力,而不是追求分数。


健康的要素是自律,而不是医疗。


爱情的基础是理解,而不是激情。


创业的要点是市场需求,而不是个人喜好。


投资的原则是风险控制,而不是高回报。


人生的追求是幸福,而不是成功。


养老的保障是提前规划,而不是依赖子女。


成长的动力是反思,而不是经历。


学习的意义是应用,而不是积累知识。


旅行的收获是见识,而不是拍照打卡。


婚姻的支撑是责任,而不是浪漫。


生活的智慧是知足,而不是无尽的欲望。 


与君共勉!愿2025活成理想的自己!


作者:河北小田
来源:juejin.cn/post/7451223580595273778
收起阅读 »

微信公众平台:天下之事合久必分分久必合

web
微信公众平台的故事,还得从 “再小的个体,也有自己的品牌” 的 Slogan 开始说起。 时间线开始 2012年8月17日 这一天,微信公众平台正式向普通用户开放,也就从这一天开始,普通人可以在微信上注册属于自己个人或组织的公众号。 2012年8月23日 这...
继续阅读 »

QQ_1734967828741.png


微信公众平台的故事,还得从 “再小的个体,也有自己的品牌” 的 Slogan 开始说起。


QQ_1734972139162.png


时间线开始


2012年8月17日


这一天,微信公众平台正式向普通用户开放,也就从这一天开始,普通人可以在微信上注册属于自己个人或组织的公众号。


2012年8月23日


这一天,微信公众平台正式上线。各大博主、媒体纷纷注册加入了这个平台,开始在微信公众平台上创作,建立自己的读者圈子,打造自己的IP。


2012年11月29日


从这天起,微信图文群发系统升级发布,图文并茂的文章可以通过微信公众平台发送给关注的粉丝了。


这时候,很多企业嗅到了春天来临的味道,招聘互联网编辑的岗位越来越多。


2013年2月6日


这一天,微信的公众号支持开发者模式了,开发者们的春天(噩梦)开始了。


很多公众号开始提供更多的功能了,比如微信公众平台文档里十年没变的那些什么话费查询、机票航班查询等:



于是公众平台开始对外提供了 “火警请按119,急救请按120” 的鸡肋开发能力——关键词回复、关注消息等。



虽然十多年过去了,我依然碰到了很多人不太理解微信公众号的这玩意的交互流程……


2013年3月19日


2013年3月20日,公众平台灰度了“自定义菜单”,当然,还只是内测。


此时的微信公众号,除了可以推送消息之外,也支持在后台编辑公众号菜单,指定菜单可以回复不同的内容或者打开一个 URL。


2013年8月5日


这天,微信发布了 v5.0 大版本,同时也带来了很多好玩的东西。


为了区分平台内公众号的各种主体,微信公众号在这一天分了家:订阅号 + 服务号。


区别在哪呢?



嗯,内测的自定义菜单给服务号开放了。但是阉割了服务号群发的频率:每月4条。



同时,对可申请的主体也做了限制:



个人只能申请订阅号了。组织类不限制。



然后当年很糟心,但现在很开心的事情发生了:订阅号从消息列表折叠到了 “订阅号” 栏目里。


好,很直接。



不过直至今日,服务号依然还可以在消息列表中直接显示。



2013年10月29日


这天,微信公众平台推出了认证的功能,认证之后有一些特权:



  • 语音识别、客服接口、获取用户地理位置、获取用户基本信息、获取关注列表和用户分组接口的权限

  • 仅认证服务号支持的 OAuth2.0网页授权、生成带参数二维码 等

  • 认证了可以送你一个



此时,微信公众号支持通过 腾讯微博新浪微博 等第三方平台的认证来同步认证服务号。此时不管是个人还是组织的号,都可以认证。但是还没有充值即认证的功能。



我猜是运营开始往赚钱上靠了,毕竟 不充钱的腾讯产品不是好产品。


2013年12月24日


说时迟那是快,这不就来了。


从今天起,你可以花 300 块钱来认证你的号了,前提是,你得是 组织 号,个人的不支持。(当然,部分类型的主体认证是不收费的,比如 政务 媒体 等)


2014年3月


今天,微信公众平台支持接入微信支付了。不过,无论你是订阅号还是服务号,都需要通过企业认证之后,再申请开通微信支付。


这一年,开发者们忙起来了。


创建订单、创建支付请求参数、签名、回调处理、支付结果查询 等等事情接踵而至。


微信开发者的圈子和生态慢慢的繁荣了起来。


2014年9月18日



哎,到哪都逃不掉 ToBCURD 业务。



随着微信开发者生态的繁荣,微信意识到了很多开发者在微信的服务号上做 ToB 的业务,要不要独立一个出来呢?


那就叫 企业号 吧,于是微信公众号的第三个兄弟也来了。


在2014年-2017年这段时间,有一个网站很火,叫 很*微信开发者社区(weixin.com)请记住这个名字,一会要考。


2016年1月11日


2016微信公开课PRO版在广州举行,那个男人(张小龙,微信之父) 首次公开演讲。


这天,张小龙说,微信要做 应用号,要让用户 用完即走


2016年5月


这段时间,上面的社区使用的 weixin.com 最终被南山必胜客拿下。手动狗头:)


2016年9月22日


微信开始内测 小程序。又一次噩梦开始了。


2016年11月3日


微信开始公测 小程序


2017年1月9日


微信小程序 正式上线。



小应用?应用号?



2017年6月29日


随着企业号的发展,微信意识到这与微信的个人社交出现了很多的冲突,于是,微信在2017年6月29日,抽离出了企业微信,牛马们开始使用这个工具来为老板创收了。


2017年12月28日


微信小游戏上线,大家一起来 打飞机


2020年1月22日


微信视频号开始内测,本文讲的微信公众平台系列故事本以为到此会结束了。然而:


2024年11月


这个月,微信把 订阅号 改名为 公众号 了。



服务号:那我呢???



我怎么总觉得有大事要发生?


最近


个人可以注册服务号了,而且注册的服务号依然是在消息列表里,还没有被折叠。



企业:??? 当年费劲巴力注册了服务号,一个月还只有四条,我的特权呢???



当然,目前注册的服务号都是没有认证的,我试了试,目前个人主体的服务号不支持认证。也就是所有的高级开发接口权限一个都没有。


我还是觉得要有大事发生了。



完全没看懂微信公众平台这个骚操作。



总结


今天简单聊了聊微信公众平台的一些小故事,如有错误,欢迎评论区指正和讨论。


只是作为曾经风风火火的微信公众平台开发者,心里感慨颇多。


Bye.


作者:Hamm
来源:juejin.cn/post/7451561994799890483
收起阅读 »

手把手教你做个煎饼小程序,摊子开起来

web
前言 周饼伦在街头摊煎饼,摊后人群熙熙攘攘。他忙得不可开交,既要记住面前小哥要加的培根,又要记住身后奶奶要加的生菜,这时又来了个小妹妹,点的煎饼既要培根又要腊肠。他把鸡蛋打进煎饼后,竟突然忘了前面光头大叔要加的料,是火腿还是鸡柳?一时记不清,好像是火腿,对。然...
继续阅读 »

前言


周饼伦在街头摊煎饼,摊后人群熙熙攘攘。他忙得不可开交,既要记住面前小哥要加的培根,又要记住身后奶奶要加的生菜,这时又来了个小妹妹,点的煎饼既要培根又要腊肠。他把鸡蛋打进煎饼后,竟突然忘了前面光头大叔要加的料,是火腿还是鸡柳?一时记不清,好像是火腿,对。然而当把煎饼交给大叔,大叔却怒了,说要的是鸡柳。😡


这可咋办?周饼伦赶忙道歉,大叔却语重心长地说:“试试用小程序云开发吧!最近的数据模型新功能好用得很!” 周饼伦亮出祖传手艺,边摊煎饼边开发小程序,把新开发的小程序点餐页面二维码贴在摊前。从此再没出过错,终于能安心摊煎饼啦!


设计思路


图片


客户扫摊子上面贴的二维码后,会进入点餐页面,在选好要加的配料之后,点击确定就可以点餐,随后,即可在云后台上看到食客提交的数据


图片


实现过程


周饼伦就把当前摊位的主食、配菜,以及各自相应的价格贴在了摊位上,也要把食客的点餐内容记在脑里或者用笔写在纸上。


点餐页要实现两个功能:1.展示当前摊位有的主食、配菜、口味 2.提交订单到周饼伦的订单页面。


煎饼摊子主食(staple food)目前只有摊饼、青菜饼,主食下面有的配菜(side dish),有鸡柳、生菜、鸡蛋、火腿、腊肠。


同理,数据库里面也需要呈现相应的结构。


数据表的实现


数据模型现在提供了一种便捷的能力来,可以快速创建一套可用的数据表来记录摊煎饼的相关数据。


图片


在云后台中新增了一个基于 MySQL 的数据模型,数据模型相当于一张纸,可以在上面记录任何想要记录的数据,比如周饼伦摊位的提供的菜品


图片


创建了基于云开发MySQL数据库的主食表,主食表中包含主食名称,主食价格


图片


图片


字段的详细设置如下


图片


图片


加了主食、配菜两个表之后,将当前的主食和配菜一起加进数据表中

图片


图片


现在就实现了记录当前摊子的主食和配菜。还需要一个订单表,来记录用户的点餐数据


图片


配菜的类型是一个数组文本,用来记录配菜的类型,结构如下


图片


接着需要分别设置每个数据模型的权限。在使用小程序查看订单时,也是以用户的身份来读取的,所以,需要配置用户权限,通过页面访问来控制用户能够访问到哪些页面


图片


图片


图片


至此,数据表就已经大功告成!现在完全可以使用三个表来记录当前摊子的菜品、营业情况。


但是,别忘了周饼伦的目的不止于此,为了周饼伦实现早日暴富,当上CEO,所以,还要利用小程序实现一个界面,来给”上帝“们点餐,并且提供各位CEO查看订单


小程序实现过程


一. 初始化 SDK


在云后台的数据管理中的右侧中,可以方便的查询到使用的文档


图片


新建一个基于云开发的小程序,删除不必要的页面,并且按照文档的步骤进行初始化👇


1.按照指引在 miniprogram 目录下初始化 npm 环境并安装 npm 包


请注意,这里需要在 miniprogram 目录下初始化 npm ,不然需要编辑 project.config.json 手动指定 npm 包的位置


在 miniprogram 目录下打开终端


图片


2.初始化当前 npm 并且安装 @cloudbase/wx-cloud-client-sdk npm 包


npm init -y & npm install @cloudbase/wx-cloud-client-sdk --save

图片


3.在小程序中构建 npm


图片


4.在小程序 app.js 中初始化环境


// app.js
App({
globalData: {
// 在这里提供全局变量 models 数据模型方法,方便给页面使用
models: null
},
onLaunch: async function () {
const {
init
} = require('@cloudbase/wx-cloud-client-sdk')
// 指定云开发环境 ID
wx.cloud.init({
env: "ju-9g1guvph88886b02",
});
const client = init(wx.cloud);
const models = client.models;
// 可以取消注释查看效果
// const { data } = await models.stapleFood.list({
// filter: {
// where: {}
// },
// pageSize: 10,
// pageNumber: 1,
// getCount: true,
// });
// console.log('当前的主食数据:');
// console.log(data.records);
}
});

二. 下单页面的实现


首先创建一个页面 goods-list 页面作为首页


顾客如果浏览下单页面,那么就需要看到当前可以选择的主食、配菜,还有他们分别的价格。所以首先我们需要把主食、配菜加载进来


// 加载主食
const stapleFood = (await models.stapleFood.list({
filter: {
where: {}
},
pageSize: 100, // 一次性加载完,
pageNumber: 1,
getCount: true,
})).data.records;

// 加载配菜
const sideDish = (await models.sideDish.list({
filter: {
where: {}
},
pageSize: 100, // 一次性加载完,
pageNumber: 1,
getCount: true,
})).data.records;

// pages/goods-list/index.js
Page({
data: {
// 总价格
totalPrize: 0,
// 选中的主食
selectedStapleFoodName: '',
// 选中的配菜
selectedSideDishName: [],
// 所有的主食
stapleFood: [],
// 所有的配菜
sideDish: [],

以下是全部的js代码


// pages/goods-list/index.js
Page({
data: {
// 总价格
totalPrize: 0,
// 选中的主食
selectedStapleFoodName: '',
// 选中的配菜
selectedSideDishName: [],
// 所有的主食
stapleFood: [],
// 所有的配菜
sideDish: [],
},

async onLoad(options) {
const models = getApp().globalData.models;
console.log('models', models)

// 加载主食
const stapleFood = (await models.stapleFood.list({
filter: {
where: {}
},
pageSize: 100, // 一次性加载完,
pageNumber: 1,
getCount: true,
})).data.records;

// 加载配菜
const sideDish = (await models.sideDish.list({
filter: {
where: {}
},
pageSize: 100, // 一次性加载完,
pageNumber: 1,
getCount: true,
})).data.records;

console.log({
stapleFood,
sideDish
});

this.setData({
stapleFood: stapleFood,
sideDish: sideDish
})
},

// 选中主食
onSelectStapleFood(event) {
this.setData({
selectedStapleFoodName: event.currentTarget.dataset.data.name
});

this.computeTotalPrize();
},

// 选中配菜
onSelectedSideDish(event) {
console.log(event);
// 选中配菜名字
const sideDishName = event.currentTarget.dataset.data.name;

// 如果已经选中,则取消选中
if (this.data.selectedSideDishName.includes(sideDishName)) {
this.setData({
selectedSideDishName: this.data.selectedSideDishName.filter((name) => (name !== sideDishName))
});
} else {
// 未选中,则选中
this.setData({
selectedSideDishName: this.data.selectedSideDishName.concat(sideDishName)
});
}

this.computeTotalPrize();
},

// 重新计算价格
computeTotalPrize() {
// 主食价格
let staplePrize = 0;
if (this.data.selectedStapleFoodName) {
staplePrize = this.data.stapleFood.find((staple) => staple.name === this.data.selectedStapleFoodName).prize;
}

// 配菜价格
let sideDish = 0;
this.data.selectedSideDishName.forEach((sideDishName) => {
sideDish += this.data.sideDish.find((sideDishItem) => (
sideDishItem.name === sideDishName
)).prize;
});

// 总价格
this.setData({
totalPrize: staplePrize + sideDish
})
},

// 提交
async onSubmit() {
// 提示正在加载中
wx.showLoading({
title: '正在提交订单',
});

const models = getApp().globalData.models;
const { data } = await models.order.create({
data: {
served: false, // 是否已出餐
sideDish: this.data.selectedSideDishName, // 配菜
stapleFoodName: this.data.selectedStapleFoodName, // 主食名称
prize: this.data.totalPrize, // 订单总价格
}
});

console.log(data);
wx.hideLoading();
}
});

接着来实现页面


<!--pages/goods-list/index.wxml-->
<view>
<view class="title">
<image src='/asset/pancake.png'></image>
<text class="title">请选择主食</text>
</view>

<!-- 主食展示 -->
<view class="staple-food">
<view wx:for="{{stapleFood}}" wx:key="_id">
<view bindtap="onSelectStapleFood" data-data="{{item}}" class="staple-food-item {{selectedStapleFoodName === item.name ? 'selected' : ''}}">
<image src="{{item.imageUrl}}"></image>
<view class="prize">{{item.prize}}¥</view>
</view>
</view>
</view>

<!-- 选择配菜 -->
<view class="title">
<image src='/asset/sideDish.png'></image>
请选择配菜
</view>

<!-- 配菜展示 -->
<view class="side-dish">
<view wx:for="{{sideDish}}" wx:key="_id">
<!-- 使得class动态绑定支持 includes 语法 -->
<wxs module="tool">
var includes = function (array, text) {
return array.indexOf(text) !== -1
}
module.exports.includes = includes;
</wxs>
<view class="side-dish-item {{tool.includes(selectedSideDishName, item.name) ? 'selected' : ''}}" bindtap="onSelectedSideDish" data-data="{{item}}">
<image src="{{item.imageUrl}}"></image>
<view class="prize">{{item.prize}}¥</view>
</view>
</view>
</view>

<!-- 底部菜单 -->
<view class="bottom-content">
<view class='bottom-info'>
<view wx:if="{{!!selectedStapleFoodName}}">主食:{{selectedStapleFoodName}}</view>
<view wx:if="{{selectedSideDishName.length !== 0}}">配菜:{{selectedSideDishName}}</view>
</view>

<view class="bottom-operate">
<view class="total-prize">当前价格<text class="prize">{{totalPrize}}¥</text></view>
<view class="submit-button {{!selectedStapleFoodName ? 'disabled' : ''}}" bind:tap="onSubmit">下单</view>
</view>
</view>
</view>

再添加一点点的样式


/* pages/goods-list/index.wxss */
.title {
display: flex;
align-items: center;
gap: 16rpx;
padding: 0 20rpx;
}

.title image {
height: 46rpx;
width: 46rpx;
}

.staple-food {
display: flex;
margin-bottom: 60rpx;
overflow: auto;
}

.staple-food-item {
margin: 20rpx 10rpx;
display: flex;
flex-direction: column;
border: 1px solid #f3f0ee;
box-shadow: 6rpx 6rpx 6rpx #dfdfdf, -6rpx -6rpx 6rpx #dfdfdf;
border-radius: 6rpx;
padding: 8rpx;
}

.staple-food-item.selected, .side-dish-item.selected {
box-shadow: 6rpx 6rpx 6rpx #58b566, -6rpx -6rpx 6rpx #58b566, 6rpx -6rpx 6rpx #58b566, -6rpx 6rpx 6rpx #58b566;
}

.staple-food-item image {
border-radius: 6rpx;
width: 300rpx;
height: 300rpx;
}

.prize {
padding: 6rpx 6rpx 0;
text-align: right;
color: orangered
}

.side-dish {
padding: 20rpx 12rpx;
display: flex;
gap: 12rpx;
overflow: auto;
}

.side-dish image {
height: 200rpx;
width: 200rpx;
}

.side-dish-item {
border-radius: 8px;
padding: 16rpx;
box-shadow: 6rpx 6rpx 6rpx #dfdfdf, -6rpx -6rpx 6rpx #dfdfdf;
}

.bottom-content {
position: absolute;
bottom: 0;
left: 0;
right: 0;
}

.bottom-info {
padding: 30rpx;
display: flex;
flex-direction: column;
color: grey;
font-size: 0.5em;
}

.bottom-content .total-prize {
padding: 0 30rpx;
}

.bottom-operate {
border-top: 1px solid #dfdfdf;
display: flex;
width: 100%;
justify-content: space-between;
align-items: center;
height: 100rpx;
}

.submit-button {
width: 350rpx;
color: white;
background: #22b85c;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}

.submit-button.disabled {
background: grey;
/* 注意,这里设置了当按钮置灰的时候,不可点击 */
pointer-events: none;
}

于是,煎饼摊的小程序就大功告成了!


接着就可以在云后台管理订单了,在将订单完成之后,即可在云后台将订单的状态修改成已完成。


图片


我们还可以做的更多…


是否可以在订单中新增一个点餐号,这样就知道是哪个顾客点的餐?是否可以使用数据模型的关联关系将配菜、主食和订单关联起来?


是否可以在小程序中创建一个管理订单的页面?是否可以添加优惠券数据表,来给客户一些限时优惠?


期待大家的体验反馈!


代码地址:github.com/vancece/qiL…


点击体验:tcb.cloud.tencent.com/cloud-admin…


作者:腾讯云云开发
来源:juejin.cn/post/7413376270518042651
收起阅读 »

这两年,我把28年以来欠的亏都吃完了...

前言 很长一段时间没有总结一下过去几个月的状态了,今天思绪万千,脑海中浮现了很多经历和生活片段,我把它记录下来。顺便今天聊一聊认知突破,分享我在买房这段时间吃过的亏,也希望作为你的前车之鉴。 买房 21年底的时候,那时刚好毕业三年,也正是互联网公司996最流行...
继续阅读 »

前言


很长一段时间没有总结一下过去几个月的状态了,今天思绪万千,脑海中浮现了很多经历和生活片段,我把它记录下来。顺便今天聊一聊认知突破,分享我在买房这段时间吃过的亏,也希望作为你的前车之鉴。


买房


21年底的时候,那时刚好毕业三年,也正是互联网公司996最流行的阶段,由于平时我不怎么花钱,也很少买衣服,上网买东西是个矛盾体,需要花很多时间对比,经常看了一件东西很久,最后又不买。加上比较高强度的工作状态,两点一线,可以说是没时间花钱,再加上自己把钱都拿去理财了,也赚了几万块,最后一共攒了几十万下来。我从小就立志要走出农村,而且认为以后有女朋友结婚也要房子,加上当时花比较多时间在理财上面,那时候其实行情已经不好了,工作上没什么突破,比较迷茫,于是想着干脆就把钱花出去了,自己也就有动力去搞各种路子尝试赚钱。在没有经过任何对比之后就在佛山买了一套房子,房价正是高峰的时候,于是我成功站岗!因为这个契机,躲过了持续了2年多的低迷股市,却没躲过低迷的房地产。


while(true) { 坑++ }


我买的是期房,当时不知道期房会有这么多坑,比如期间不确定开发商会不会破产,我这个开发商(龙光)就差点破产了,房产证无着落,相当于花了200w买了一个无证的房子,这辈子就算是搭进去了。


对于整个购房过程也是很懵逼,对流程完全不熟悉,当时去翻了政府规划文件,看那个地段后续有没有涨价空间,然后跟着亲戚介绍的销售转圈圈,当时说给我免3年物业费,合计也有几万块。在签合同之前销售都有说可以给到,但由于第一次没有录音,导致在签合同的时候销售反口,不承认,我们也没有证据,最后吃了哑巴亏。


开始的时候谈好了一个价格167w,然后销售私下打电话给我洗脑说我给点辛苦费1.5w,他可以向领导申请多几万块优惠。我知道这是他们的销售套路,但是架不住给我优惠5w啊,中间反复拉扯最后说给他8k,采用线下现金交易的方式。这一次我有录音了,因为私底下交易没有任何痕迹,也不合法,所以留了一手,也成为我后面维权时争取话语权的基础。


中介佣金是很乐观的,当时由于我亲戚推荐我去,销售承诺税前有4w,当时看中这个返佣也促使我火急火燎的交了定金。现在3年过去了,这个佣金依旧没有到账,我一度怀疑是中介搞ABC套路把我这个钱💰吃了,其他邻居的推荐佣金都到了账,加上现在地产商没钱了,同时跟那个亲戚有些过节,这个返佣更是遥遥无期。最后通过上面的录音获得了一丝话语权,知道了这个钱还在开发商手上,一直没有拨款下来到中介公司。下面是部分聊天记录:


image.png


不接受微信语音沟通,文字可以留给自己思考的时间,同时也更好收集证据。


image.png


然后去找相关人员把信息拉出来给我看,显示开发商未付款状态,这个状态维持2年了,目前看来只能再等下去。


image.png


签合同的时候,有个律师所说是协助我们签合同、备案、办房产证等各种边缘工作,糊里糊涂交了700元律师费,不交不行,甚至律师所连发票都没有给,而我都没有意识到这个最基本的法律法规问题。现在交房了可以办理房产证了,拿证下来也就80块登记费,居然收我700,其他业主有些是600多,400多,顿时觉得智商受到了侮辱,看了网上铁头各种打假的视频,我觉得自己也应该勇敢发声。现在也在收集商家各种违规证据,提交给相关部门解决。


image.png


image.png


image.png


后面市场监督管理局收到投诉,应该是有协商,意识到没有给我们发票,过来几天之后才把发票补过来,开票日期不是付款时候的2022年,而是2024年,明显属于偷税了。目前跟他要发票的应该只有我,估算2300多户业主都没有开发票的。


当时我首付需要50w,自己手上不够,我爸干建筑一辈子,辛苦供我们两个孩子上了大学,山上建了两层楼,手里没钱。我妈是一辈子没打过工,消极派,说出来没几句好话,家里不和睦的始作俑者,更不可能有钱支持。所以我还有20w是首付贷,也就是跟开发商借的,利率10%,这个利息很高了。销售当时说可以优惠到5%,但是优惠金额是补贴到总房价里面去,其实这也是他们的一种销售套路,这亏我也吃了,2年之后我连本带息还24w。当时认为自己应该一年左右能还完,但是实际远远高估自己的能力,买完房子接着我爸又生病在医院待了几个月,前后花了十几万,人生一下子跌入了谷底。


从头再来


后面2023一年,夫妻出去创业,很多人不赞同,期间遇到了不少小人诋毁我们两夫妻,当时我老婆还在怀孕,但我们最后都熬过来了,还生了一个儿子,6斤多。期间一年赚了十几万,但是开支也大,加上父母要养,我爸还要吃药,房子要供,最后还是选择了先稳定下来,我重新回到了职场,空窗一年后在这个环境下拿了一个还不错的offer,同时也想自己沉淀一下。


自从有了宝宝之后,生活似乎都往好的方面发展,出版社找我出书,为了契合自己的职业发展,我选择了写书《NestJS全栈开发秘籍》,从2023年11月份开始,迄今快半年了,在收尾阶段,希望尽快与各位读者们见面。同时,等了3年的房子也收房了,由于是高层,质量相对其他邻居好,没有出现成片天花掉下来或者漏水的情况。我们经常都说他是天使宝宝,是来报恩的。


由于我们公司技术部门是属于后勤支持性质的,技术变化不大,Vue2+微前端和React管理系统那一套,没有太多的新技术扩展,意味着不确定也大。业务发展不好考虑的是减少这些部门的开支,所以不出意外最近也迎来了降薪。这不是最可怕的,对于我们技术人来讲,最可怕的是我认为在业务中成长停滞了,或者没有业务来锻炼技术,所以在业余时间也选择了参与一些开源项目,如hello-alog开源算法书的代码贡献,并且这也是选择写书的原因。很简单地说,当下一个面试官问到我的时候,我不可能什么都讲不出来,最经典的问题就是:在这个公司期间你做过最有成就感的事情是什么?现在,我有了答案!


哲学


我的人生哲学是不断改变,拥抱不确定性!这么看来,我的确在这些年上了不少当,吃了不少亏,把自己搞的很累,甚至连累到家里人。但,用我老婆经常说的一句话:人生这么长,总是要经历点什么,再说现在也没有很差。的确,不断将自己处于变化之中,当不确定性降临到普罗大众时,我们唯一的优势,就是更加从容


总结


人们还在行走,我们的故事还在继续~


WechatIMG154.jpg


作者:元兮
来源:juejin.cn/post/7349136892333981711
收起阅读 »

运维打工人,周末兼职送外卖的一天

运维打工人,周末兼职送外卖的一天 在那个不经意的周末,我决定尝试一份新的工作——为美团外卖做兼职配送员。这份工作对于一向规律生活的我来说,既是突破也是挑战。 早晨,城市的喧嚣还未完全苏醒,空气中带着几分凉意和宁静。准备好出发时,线上生产环境出现问题,协助处理。...
继续阅读 »

运维打工人,周末兼职送外卖的一天


在那个不经意的周末,我决定尝试一份新的工作——为美团外卖做兼职配送员。这份工作对于一向规律生活的我来说,既是突破也是挑战。


早晨,城市的喧嚣还未完全苏醒,空气中带着几分凉意和宁静。准备好出发时,线上生产环境出现问题,协助处理。


收拾好后,戴上头盔,骑上踏板车,开始了自己的第一次外卖配送之旅。


刚开始,我的心情既紧张又兴奋。手机里的订单提示声是今日的任务号角。第一份订单来自一公里外的一家外卖便利店。我快速地在地图上规划路线,开启高德导航,发动踏板车,朝着目的地出发。


123.jpg


由于便利店在园区里面,转了两圈没找到,这是就慌张了,这找不到店咋办了,没办法赶紧问下旁边的老手骑手,也就顺利找到了,便利店,进门问老板,美团104号好了嘛?老板手一指,在架子上自己看。核对没问题,点击已达到店,然后在点击已取货。


然后在导航去收获目的地,找到C栋,找到107门牌号,紧接敲门,说您好,美团外卖到了,并顺利的送达,然后点击已送达,第一单顺利完成,4.8元顺利到手。


其中的小插曲,送给一个顾客时,手机导航提示目的地,结果一看,周围都拆了。没办法给顾客打电话,加微信确认位置具体在哪里,送达时,还差三分钟,这单就要超时了。


1.jpg


配送过程中,我遇到了第一个难题:找不到店家在哪里,我的内心不禁生出些许焦虑。但很快,我调整心态,不懂不知道的地方,需要多多问人。


紧接着,第二份、第三份订单接踵而至。每一次出发和到达,每一条街道和巷弄,我开始逐渐熟悉。


7.jpg


6.jpg


日落时分,我结束了一天的工作。虽然身体有些疲惫,但内心充满了前所未有的充实感。这份工作让我体验到了不一样的人生角色,感受到了城市节奏背后的种种辛劳与甘甜


周末的兼职跑美团外卖,对我来说不仅是一份简单的工作,更是一段特别的人生经历。它教会了我坚持与责任,让我在忙碌中找到了属于自己的节奏,在逆风中学会了更加珍惜每一次到达。


最后实际周六跑了4个小时,周天跑了7个小时,一共跑了71公里,合计收获了137.80,已提现到账。


5.jpg


2.png


作者:平凡的运维之路
来源:juejin.cn/post/7341669201010425893
收起阅读 »

代码与蓝湖ui颜色值一致!但页面效果出现色差问题?

web
前言 最近在开发新需求,按照蓝湖的ui图进行开发,但是在开发完部署后发现做出来的页面部分元素的颜色和设计图有出入,有色差!经过一步步的排查最终破案,解决。仅以此篇记录自己踩坑、学习的过程,也希望可以帮助到其他同学。 发现问题 事情是这样的,那是一个愉快的周五的...
继续阅读 »

前言


最近在开发新需求,按照蓝湖的ui图进行开发,但是在开发完部署后发现做出来的页面部分元素的颜色和设计图有出入,有色差!经过一步步的排查最终破案,解决。仅以此篇记录自己踩坑、学习的过程,也希望可以帮助到其他同学。


发现问题


事情是这样的,那是一个愉快的周五的下午,和往常一样我开心的提交了代码后进行打包发版,然后通知负责人查看我的工作成果。


但是,过了不久后,负责人找到了我,说我做出来的效果和ui有点出入,有的颜色有点不一样。我一脸懵逼,心想怎么可能呢,我是根据ui图来的,ui的颜色可是手把手从蓝湖复制到代码中的啊。


随后他就把页面和ui的对比效果图发了出来:


image.png


上图中左侧是蓝湖ui图,右侧是页面效果图。我定睛一看,哇趣!!!好像是有点不一样啊。 感觉右侧的比左侧的更亮一些。于是我赶紧本地查看我的页面和ui,果然也是同样问题! 开发时真的没注意,没发现这个问题!!!


排查问题


于是,我迅速开始进行问题排查,看看到底是什么问题,是值写错了?还是那里的问题。


ui、页面、代码对比


下图中:最上面部分是蓝湖ui图、下面左侧是我的页面、右侧是我的页面代码样式


image.png


仔细检查后发现颜色的值没错啊,我的代码中背景颜色、边框颜色的值都和ui的颜色值是一致的! 但这是什么问题呢??? 值都一样为什么渲染到页面会出现色差?


起初,我想到的是屏幕的问题,因为不同分辨率下展示出来的页面效果是会有差距的。但是经过查看发现同事的win10笔记本、我的mac笔记本、外接显示器上都存在颜色有色差这个问题!!!


ui、页面、源文件对比


通过对比ui、页面、颜色值,不同设备展示效果可以初步确认:和显示器关系不大。当我在百思不解的时候,我突然想到了ui设计师!ui提供的ui图是蓝湖上切出来的,那么她的源文件颜色是什么呢?


于是我火急火燎的联系到了公司ui小姐姐,让她发我源文件该元素的颜色值,结果值确实是一样的,但是!!! 源文件展示出来的效果好像和蓝湖上的不太一样!


然后我进行了对比(左侧蓝湖、右上页面、右下源文件):


image.png


可以看到源文件和我页面的效果基本一致!到这一步基本可以确定我的代码是没问题的!


尝试解决


首先去网上找了半天没有找到想要的答案,于是我灵光一现,想到了蓝湖客服!然后就询问了客服,为什么上传后的ui图内容和源文件有色差?


image.png


image.png


沟通了很久,期间我又和ui小姐姐在询问她的软件版本、电脑版本、源文件效果、设置等内容就不贴了,最终得到如下解答:


image.png


解决方式


下载最新版蓝湖插件,由于我们的ui小姐姐用的 sketch 切图工具,然后操作如下:


1.下载安装最新版蓝湖插件: lanhuapp.com/mac?formHea…


2.安装新版插件后--插件重置


3.后台程序退出 sketch,重新启动再次尝试打开蓝湖插件.


4.插件设置打开高清导出上传(重要!)


5.重新切图上传蓝湖


最终效果


左侧ui源文件、右侧蓝湖ui:
image.png


页面效果:


image.png


可以看到我的页面元素的border好像比ui粗一些,感觉设置0.5px就可以了,字体效果的话是因为我还没来得及下载ui对应的字体文件。


但是走到这一步发现整体效果已经和ui图到达了95%以上相似了,不至于和开始有那么明显的色差。


总结


至此,问题已经基本是解决。遇到问题不能怕,多想一想,然后有思路后就一步一步排查、尝试解决问题。当解决完问题后会发现心情舒畅!整个人都好起来了,也会增加自信心!


作者:尖椒土豆sss
来源:juejin.cn/post/7410712345226035200
收起阅读 »

基于Vue.js和高德地图API来实现一个简易的天气预报

web
今天就让我们来使用 Vue.js 和高德地图开放平台提供的 API,实现一个关于天气预报的小demo,实时查询当前城市的天气以及未来三天的天气预测,且实现切换城市查询。实现效果如下; 准备工作 既然要使用真实的数据,那么就需要用到高德地图开放平台提供的天气查...
继续阅读 »

今天就让我们来使用 Vue.js 和高德地图开放平台提供的 API,实现一个关于天气预报的小demo,实时查询当前城市的天气以及未来三天的天气预测,且实现切换城市查询。实现效果如下;


PixPin_2024-12-15_00-13-38.gif


准备工作


既然要使用真实的数据,那么就需要用到高德地图开放平台提供的天气查询 API,先高德地图api注册为开发者。然后点击文档与支持,选择JS API。


image.png


然后登录到控制台创建一个应用并且添加一个key,服务平台为Web端(JS API)。
16b5ba85e6c5f128b699fe8d521bb67.jpg


终端npm create vite@latest使用vite创建项目,npm install下载该项目需要用的包,npm run dev运行项目。


image.png


将天气预报的功能全部开发在weather.vue里面,再将这个组件import weather from "./components/weather.vue"引入到app.vue中。


image.png


js代码概览


image.png


具体代码步骤实现


开始weather.vue里面的代码了。


html 部分


<div>
// 头部
<div class="head">
<div class="city-name">
<i class="iconfont icon-dingwei"></i>
{{ state.city }}
</div>
<div @click="toggle" class="city-change">
<i class="iconfont icon-24gf-city3"></i>
切换城市
</div>
</div>


// 中间部分实时温度
<div class="main">
<div class="weather-info">
<p class="temp">{{ state.weather.temperature }}℃</p>
<div class="info">{{ state.weather.weather }}</div>
<div class="detail">
<div class="item">
<i class="iconfont icon-shuidi"></i>
<span>湿度</span>
<span>{{ state.weather.humidity }}</span>
</div>
<div class="item">
<i class="iconfont icon-feng"></i>
<span>风向</span>
<span>{{ state.weather.windDirection }}</span>
</div>
<div class="item">
<i class="iconfont icon-fengli"></i>
<span>风力</span>
<span>{{ state.weather.windPower }}</span>
</div>
</div>
</div>

// 未来三日的天气预报
<div class="future">
<div class="future-title">三日天气预报</div>
<div class="future-content">
<div v-for="(item,i) in state.future" class="forecast">
<p class="week">周{{ chinese[Number(item.week)-1] }}</p>
<i :class="getWeatherIcon(item.dayWeather)"></i>
<p><span class="left">{{ item.dayTemp }}℃</span> <span class="right"> / {{ item.nightTemp }}℃</span></p>
</div>
</div>
</div>
</div>


// 切换城市input框
<div v-show="state.isVisible" >
<input id="newCity" @keydown.enter="handle" type="text" v-model="state.newCity" placeholder="请输入你要查询的城市">
</div>
</div>


然后使用css样式美化成如下界面


image.png


js部分


接下来就是渲染其中的数据了,首先使用高德 api 来获取定位数据,查看官方文档,JS API结合 Vue 使用,首先安装Loader,如下所示,复制到当前文件终端安装。
image.png


然后复制代码粘贴;
image.png


AMapLoader 是高德地图 js API 的加载器,它可以在前端项目中加载和初始化高德地图的 js API。


import AMapLoader from '@amap/amap-jsapi-loader';
import { onMounted, reactive } from 'vue'

onMounted(() => {   // 在浏览器上出现内容时候触发
// 加载官方提供的方法
window._AMapSecurityConfig = {
securityJsCode: "", // 密钥
};
AMapLoader.load({
key: "", // 申请好的Web端开发者Key,首次调用 load 时必填
version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins: ["AMap.Scale"], //需要使用的的插件列表,如比例尺'AMap.Scale',支持添加多个如:['...','...']
})

// 加载完上面代码高德提供的服务后,执行then后面的操作
.then((AMap) => {
// 获取定位
getLocalCity(AMap) // 使用一个函数,将获取地址信息放到这个函数中
})
})

获取城市信息


官方文档:
image.png


const getLocalCity = (AMap) => {
AMap.plugin('AMap.CitySearch', function () {
var citySearch = new AMap.CitySearch()
citySearch.getLocalCity(function (status, result) {
if (status === 'complete' && result.info === 'OK') {
// 查询成功,result即为当前所在城市信息
console.log(result.city); // 会打印当前城市
state.city = result.city //将城市改为定位获取到的城市
getWeather(AMap) // 获取天气
}
})
})
}

image.png


利用该地址获取实时天气数据
image.png


const getWeather = (AMap) => {
//加载天气查询插件
AMap.plugin("AMap.Weather", function () {
//创建天气查询实例
var weather = new AMap.Weather();
//执行实时天气信息查询
weather.getLive(state.city, function (err, data) { // 将城市替换成state.city
console.log(err, data); // 获取天气数据,详情见下表
state.weather = data // 将数据赋值给 state.weather
getForecast(AMap) // 后面用来获取未来三天的天气
});
});
}

image.png
将这一整个对象赋值给state.weather然后再state.weather.渲染到页面上。


获取未来三天天气


const getForecast = (AMap) => {
AMap.plugin("AMap.Weather", function () {
//创建天气查询实例
var weather = new AMap.Weather();
//执行实时天气信息查询
weather.getForecast(state.city, function (err, data) {
console.log(err, data);
state.future = data.forecasts // 获取天气预报数据

//err 正确时返回 null
//data 返回天气预报数据,返回数据见下表
});
});
}

image.png


最后就是切换城市中的input框的实现;


<div v-show="state.isVisible" >
<input id="newCity" @keydown.enter="handle" type="text" v-model="state.newCity" placeholder="请输入你要查询的城市">
</div>

添加以一个v-show方法,然后绑定一个键盘敲击事件触发handle,并用v-model获取输入的数据并将其存储到state.newCity


const handle = () => {
state.isVisible =!state.isVisible // 回车键将框不显示
state.city = state.newCity // 城市变为输入的城市
getWeather(AMap) // 重新获取该城市天气以及该城市未来天气
}

const toggle = () => {
state.isVisible =!state.isVisible // 使得点击切换城市框会显示和消失
}

以上就是实现获取定位城市,该城市的实时天气,以及未来三天的天气预测,切换查询其它城市的功能具体代码了。


总结


以上使用了Vue.js 组件化的方式来构建界面,利用高德地图 API 获取定位和天气数据,利用 Vue 的响应式机制来实时更新页面数据,通过使用官方文档中 AMapLoader 加载高德地图的JS API,使得我们能高效处理地图相关功能,希望这个小 demo 能够对你的前端开发有所帮助,同时记得给文章点点赞哦🤗。


image.png


作者:六个点
来源:juejin.cn/post/7448246468471521307
收起阅读 »