Skip to main content

ant design 的表格懒加载

· 4 min read
阿毛
人生得意须尽欢

大家好,我是一名,跨境行业 saas 软件开发的前端程序员,阿毛

这个我的个人网站

我们公司的一个项目前端是用 ant design 开发的,这个表格内的东西比较多, 导致比较卡,本来想说用虚拟列表的,只加一个配置就行了,但是在表格内部又多一个滚动条,影响用户体验, 想到了懒加载,调研了一下,这里就做了一个 demo 来看看效果。

我这里点击 load 加载了一个 50 列,1000 行的 表格, 感觉还行,没有什么卡顿。

alt text

这里是用了 react-lazyload 这个库 ,这里简单讲一下使用步骤

  1. 安装

    • yarn add react-lazyload
    • yarn add @types/react-lazyload
    • yarn add prop-types
  2. 在 antd 中使用

  • placeholder 可以写未加载时显示的东西 我这里不显示 为null
  • height 为这个组件 未加载时的 站位高度
  • scrollContainer 是一个很重要的配置, 是你滚动的的那个dom元素, 这里是body 就不用配置了
  • 还有一些其他配置可自行查阅
<Table
sticky
loading={loading}
dataSource={data}
columns={columns}
scroll={{ x: 800 }}
components={{
body: {
row: (_props) => {
return (
<LazyLoad placeholder={null} height={54}>
<tr {..._props} />
</LazyLoad>
);
},
},
}}
pagination={false}
/>
  1. 样式修复

使用 react-lazyload 进行懒加载时, 它会默认给你加一个 类为 lazyload-wrapper 的 div 来进行包裹, 在其他地方可能影响不大, 但是在表格中,如果你有一些自己的样式,就会被影响到, 这里为了消除影响, 让 lazyload-wrappe 下 有 tr 的 div 不参与样式计算中,这样来消除影响。

/* 样式 */
div.lazyload-wrapper:has(> tr) {
display: contents !important;
}
以下是demo 的全部代码
import { useMemo, useState } from 'react'
import LazyLoad from 'react-lazyload';
import './App.css'
import { Button, Table } from 'antd'
import { ColumnsType } from 'antd/es/table';


function App() {
const [loading, setLoading] = useState(false)
const [data, setData] = useState([])

const columns: ColumnsType<any> = useMemo(() => {
const arr = []
for (let i = 0; i < 50; i++) {
const str = "value" + i
arr.push(
{
title: str,
dataIndex: str,
key: str,
width: 100,
render: (text) => {
return (
<span>{text}</span>
)
}
}
)
}
return arr
}, [])

function getData() {
const arr = []
console.log('run loading')
setLoading(true)
setTimeout(() => {
for (let j = 0; j < 1000; j++) {
const obj: any = {}
for (let i = 0; i < 50; i++) {
obj[`value${i}`] = Math.random()
}
arr.push(obj)
}
console.log('OK')
console.log(arr)
setData(arr)
setLoading(false)
}, 1000);
}

return (
<>
<Button onClick={() => getData()}>load</Button> {data.length}

<Table
sticky
loading={loading}
dataSource={data}
columns={columns}
scroll={{ x: 800 }}
components={{
body: {
row: (_props) => {
return (
<LazyLoad placeholder={null} height={54}>
<tr {..._props} />
</LazyLoad>
)
}
}
}}
pagination={false}
/>

</>
)
}
export default App

用 Electron 从 0 开发一个桌面软件(三)

· 4 min read
阿毛
人生得意须尽欢

大家好,我是一名,跨境行业 saas 软件开发的前端程序员,阿毛

这个我的个人网站

alt text

用 Electron 从 0 开发一个桌面软件,决定做一个视频转码软件,第三天。

最近没什么空,公司让我改个JSP的项目,折腾了两天。前两天改的东西验收上线了, 现在来继续做做我的格式转换器。

前端的代码我都没有这么写,都是用deepseek 生成的,生成完之后我在改改。 今天做好了可以批量选择视频进行格式转换,可以设置存储路径。

  1. 这次主要遇到的有两个小问题
  • 本来以为在渲染进程通过 input 就直接能获取,但是试了之后发现其实有些信息书获取不到的, 比如帧数, 码率等。后面有采用和转码同样的方式,先传到主进程,生成文件,再通过 ffmpeg.ffprobe 来进行获取

function getVideoDetail(fileInfo: fileInfoDTO): Promise<VideoDetailDTO | null> {
return new Promise(async (resolve) => {
const url = await tempVideo(fileInfo)
fs.stat(url, (err, stats) => {
if (err) {
resolve(null)
return
}
const fileSizeInBytes = stats.size
const fileSizeInMB = (fileSizeInBytes / (1024 * 1024)).toFixed(2)

ffmpeg.ffprobe(url, (err, metadata) => {
if (err) {
console.error('获取视频元数据时出错:', err)
resolve(null)
return
}

// 获取视频流
const videoStream = metadata.streams.find((stream) => stream.codec_type === 'video')
// const audioStream = metadata.streams.find((stream) => stream.codec_type === 'audio')

if (videoStream) {
const frameRateArray = videoStream.r_frame_rate.split('/');
const frameRate = parseInt(frameRateArray[0], 10);
console.log(frameRate);

const obj: VideoDetailDTO = {
url: url,
name: fileInfo.name,
size: fileSizeInMB,
width: videoStream.width,
height: videoStream.height,
duration: metadata.format.duration,
codec_name: videoStream.codec_name,
r_frame_rate: frameRate,
bit_rate: Number((videoStream.bit_rate / 1000).toFixed(0)),
color_space: videoStream.color_space,
format_name: metadata.format.format_name
}
resolve(obj)
} else {
resolve(null)
}
})
})
})
}

  1. 文件存储路径的选择,我本来以为和 input 上传一样,选择一个文件夹即可, input 选择之后呢也获取不到真实的地址的, 后来搜了一下用了 electron 的 dialog 模块来选择目录

主进程

/**
* 选择 目录
* @param map
* @param event
* @param obj
*/
SELECT_FOLDER: (map: getMapFuns, event: Electron.IpcMainEvent): void => {
console.log('---')
const win = map?.getMainWin?.()
if (win) {
dialog.showOpenDialog(win, {
properties: ['openDirectory'] // 设置属性为 'openDirectory' 以仅打开目录选择器。
}).then(result => {
console.log(result)
if (!result.canceled) { // 检查用户是否点击了取消按钮。
event.reply('SELECT_FOLDER_RESP', result.filePaths[0])
} else {
event.reply('SELECT_FOLDER_RESP', null)
}
}).catch(err => {
console.error(err); // 处理可能的错误。
event.reply('SELECT_FOLDER_RESP', null)
});
}
}

下次更新先吧格式转换进度做出来

后面我想继续做的可能有几个功能

  • 视频和音频的格式转换
  • 视频的切片
  • 定时任务,每隔一段时间扫描指定文件夹, 如果有新的未转换格式的文件,就去转换后放到指定文件夹 (这个需求是我家的nas,下载的视频,有写格式播放不了,手动去转有点麻烦,做了这个功能后以后自动扫描文件,就不用手动去转格式了 )

第四周:再次体验JSP

· 3 min read
阿毛
人生得意须尽欢

大家好,我是一名,跨境行业saas软件开发的前端程序员,阿毛

我们公司有一个老的项目,也是我们的主营业务,好多年了,我看代码提交都有两万多次了,前端是JSP。 这周让我去改改原来英文版本的价格页。 对于改JSP, 感觉有一个固有印象, 就是尽量别动,感觉很难改, 后端不想碰,前端也不愿意碰。

这周让我改这个,3月7号出了需求,3月11号出了设计图,3月13号,我还一行代码都没有提交。 为什么呢?, 中间的波折真是难搞,倒不是因为JSP的难改,而是环境配置。我就请求了我们的后端帮助, 帮我部署,第一个后端用的是window (有第一肯定有就第二), 我win的电脑只有家里的,我就让他 在我家里的那台电脑上部署,中间也是折腾了几个小时, 终于部署上了,后面就在我的家用电脑上进行开发, 没想到,我那个电脑16G的内存,拖不动这个项目,勉强跑起来,内存到90%了,页面根本点都点不动, 不要说开发了, 哎,恼火。没法,我又请求了第二个是用mac的后端帮助,在我这台mac上配置, 中间又折腾了几个小时。终于跑起来, 我的这台mac 也是16G的, 感觉mac的16G确实要比 win的16G 强太多,确实跑起来都还是比较流畅。 在这里呢,还是要再次感谢公司的那两位同事,他们不帮我配置,我还真跑不起来。

然后呢就昨天14号,改JSP, 电脑流畅了,我感觉改JSP还挺好的,数据Java的都设置过来了, 直接就是判断显示, 给我的体验还不错,昨天也都改的七七八八了,周末在加加班,应该就没啥问题了。

用 Electron 从 0 开发一个桌面软件(二) ffmpeg 在 Electron 中的使用

· 6 min read
阿毛
人生得意须尽欢

大家好,我是一名,跨境行业 saas 软件开发的前端程序员,阿毛

这个我的个人网站

用 Electron 从 0 开发一个桌面软件,决定做一个视频转码软件,第二天。

今天做了一下调研,发现一个库ffmpeg ,无论是编码格式,视频拼接,裁剪,音频分离,混流,图片处理等等都很方便的进行处理,我用ffmpeg 做了一下测试,发现确实很好用

但是呢 ffmpeg 需要先进行安装, 我打包成桌面应用之后,万一用户没有安装,咋办,那我的功能不就用不了了吗?

问了一下AI,他给我两个方案

  • 一个是,在运行时检测是否安装ffmpeg,没有安装的话,就提示去安装后才能使用。
  • 另一个是把 ffmpeg的 执行文件一起打包到 Electron 中

我觉得第二个方案应该要好一点,但是怎么才能把执行文件一起打包呢, 找了一下发现了 ffmpeg-static , 里面放的就是可执行文件, 用 ffmpeg.setFfmpegPath 设置可执行文件路径 ,完美解决。

    const ffmpeg = require("fluent-ffmpeg");
const ffmpegPath = require('ffmpeg-static');
ffmpeg.setFfmpegPath(ffmpegPath);

OK 开始做吧。

但是做的时候呢又遇到一个问题,input 上传文件呢,是拿不到文件的真实地址的,而 ffmpeg 是需要真实地址的 后来又折中了一下,拿到file之后呢,传给主进程,主进程生成一个临时文件,在用这个临时文件去转码,OK 完美解决

下一步呢,我准备先美化一下页面,看看别的转码软件都有哪些功能,我再加点类似的功能

视频转码demo

这是页面代码

页面很简单就, 一个 input 和 测试转码 的按钮 点击会把 input 选的文件传给主进程 进行转码,现在转码的输出文件是写死的

import { useState } from "react"

function App(): JSX.Element {
const [file, setFile] = useState<any>(null)

const [fileInfo, setFileInfo] = useState<any>(null)

const handleFileChange = (event): void => {
const _file = event.target.files[0];
setFile(_file)
const reader = new FileReader();
reader.onload = (e): void => {
const fileContent = e?.target?.result;
// 这里可以将 fileContent 和文件名等信息一起传递给主进程
const fileInfo = {
name: _file.name,
content: fileContent
};
setFileInfo(fileInfo)
};
reader.readAsArrayBuffer(_file)
};

const testFun = (): void => {
window.electron.ipcRenderer.send('VIDEO_CONVERSION_API', {
fileInfo: fileInfo,
outputFilePath: '/Users/mao/code/electron/ElectronConvert/output.mp4'
})
}

return (
<>
<div className="max-w-md mx-auto p-6 space-y-6">
{/* 文件上传区域 */}
<div className="space-y-4">
<label className="block">
<span className="sr-only">选择文件</span>
<input
type="file"
onChange={handleFileChange}
className="block w-full text-sm text-gray-500
file:mr-4 file:py-2 file:px-4
file:rounded-full file:border-0
file:text-sm file:font-semibold
file:bg-blue-50 file:text-blue-700
hover:file:bg-blue-100"
/>
</label>

{/* 操作按钮 */}
<button
onClick={testFun}
className={`w-full py-3 px-6 rounded-lg font-medium transition-all
${file ?
'bg-blue-600 text-white hover:bg-blue-700' :
'bg-gray-100 text-gray-400 cursor-not-allowed'}`
}
>
测试转码
</button>
</div>

{/* 文件信息 */}
{file && (
<div className="p-4 bg-gray-50 rounded-lg border border-gray-200">
<p className="text-sm font-medium truncate">{file.name}</p>
<p className="text-xs text-gray-500 mt-1">
{Math.round(file.size / 1024)} KB · {file.type}
</p>
</div>
)}
</div>
</>
)
}

export default App



这是主进程中的主要代码

import ffmpeg from 'fluent-ffmpeg'
import ffmpegPath from 'ffmpeg-static'
ffmpeg.setFfmpegPath(ffmpegPath)
import fs from 'fs'
import path from 'path'
import { tmpdir } from 'os'

interface fileInfoDto {
name: string
content: any
}

// 将 timemark 字符串转换为秒
function timemarkToSeconds(timemark): number {
const parts = timemark.split(':')
const hours = parseInt(parts[0], 10)
const minutes = parseInt(parts[1], 10)
const seconds = parseFloat(parts[2])
return hours * 3600 + minutes * 60 + seconds
}

// 生成文件返回地址
const tempVideo = (fileInfo: fileInfoDto): Promise<string> => {
return new Promise((resolve) => {
const { name, content } = fileInfo
// 生成临时文件路径
const tempFilePath = path.join(tmpdir(), name)
// 将文件内容保存为临时文件
fs.writeFile(tempFilePath, Buffer.from(content), (err) => {
if (err) {
console.error('保存临时文件出错:', err)
resolve('')
return
}
resolve(tempFilePath)
})
})
}

const VideoConversion = async (options: { fileInfo: fileInfoDto; outputFilePath: string }) => {
console.log(options)
const inputFilePath = await tempVideo(options.fileInfo)
let totalFrames = 0
if (inputFilePath) {
// ffmpeg -i /var/folders/h7/zj0ytbjd62x1b7kp7f7t9_9c0000gn/T/录屏2025-03-09 10.53.04.mov -y /Users/mao/code/electron/ElectronConvert/o.mp4
ffmpeg(inputFilePath)
.output(options.outputFilePath)
.on('start', (commandLine) => {
console.log('开始转码: ' + commandLine)
})
.on('codecData', (data) => {
totalFrames = timemarkToSeconds(data.duration)
console.log('视频长度', totalFrames, '秒')
})
.on('progress', (progress) => {
const timemark = progress.timemark
// 将 timemark 转换为秒
const currentTime = timemarkToSeconds(timemark)
const progressPercentage = (currentTime / totalFrames) * 100
console.log(`当前转码进度: ${progressPercentage.toFixed(2)}%`)
})
.on('end', () => {
console.log('转码完成')
})
.on('error', (err) => {
console.error('转码出错: ' + err.message)
})
.run()
}
}

export default {
VideoConversion,
tempVideo
}


用 Electron 从 0 开发一个桌面软件(一)

· 2 min read
阿毛
人生得意须尽欢

大家好,我是一名,跨境行业 saas 软件开发的前端程序员,阿毛

这个我的个人网站

我是一名前端程序员,其实很久之前就知道 Electron, 也折腾过一段时间,主要是了解了一下主进程,渲染进程什么的, 但是呢一直没有做过什么东西,最近呢,在写博客,要不做一个 electron 的桌面软件? 正好博客的内容也有了。

做什么呢? 不能太简单也 不能太难。

想了一下,想到一件事儿:有一次我的车被剐蹭了,我的行车记录仪呢,是那种老的, 插U盘的,后来呢我就吧我的U盘拔下来 插到电脑上,想看一下当时的视频,结果呢电脑打开了,看到视频格式呢是 h.265 , 我以前呢都没有见过这种格式,我电脑也 打不开,结果就到网上去搜索格式转换器,结果一连下了好几个,开始下载的时候,标题都是说是免费的,真用的时候就让你冲 会员,把我给气的。 好,这次就做这个视频的格式转换器了。

好,确定了做什么,那今天就先把框架搭一搭

我决定用 electron-vite 来搭建项目, tailwindcss 来做样式

... OK 倒腾了一下,项目搭建完成,tailwindcss 也整合进去了,明天开始正式编码

alt text

第三周:Puppeter 如何链接控制 Electron 创建的窗口

· 2 min read
阿毛
人生得意须尽欢

大家好,我是一名,跨境行业 saas 软件开发的前端程序员,阿毛

这个我的个人网站

最近想用 Electron 做一个爬虫,想到用 Puppeter 来控制 Electron 创建的窗口执行爬取任务。 网上找了很多方法都不好用, 最后发现一个库可以链接 Electron 和 Puppeter , 这里分享一下

puppeteer-in-electron

这是我的页面 就一个按钮

const Index = () => {
const ipcRenderer = window.electron.ipcRenderer;
function open() {
ipcRenderer.send("openBaidu");
}
return (
<div className="w-full h-full flex justify-center items-center">
<Button onClick={() => open()}>打开百度</Button>
</div>
);
};

这是主进程的方法

这是主进程的方法 createPupPage 我做了一个简单的处理, 传入一个 url ,通过 Electron 创建一个窗口 ,通过 puppeteer 接管后 返回 page, 然后输入 DeepSeek 点击确定 然后等待 1 秒, 最后截图

ipcMain.on("openBaidu", async () => {
console.log("pong");
const page = await createPupPage({ loadURL: "https://www.baidu.com/" });
await page.type("#kw", "DeepSeek");
await page.click("#su");
await wait(1000);
await page.screenshot({ path: "baidu.png" });
});

createPupPage 相关代码

import { app, BrowserWindow } from "electron";
import puppeteer, { Page } from "puppeteer-core";
const pie = require("puppeteer-in-electron");

let browser = null;

export function getBrowser(): unknown {
return browser;
}
export async function init(): Promise<void> {
await pie.initialize(app);
browser = await pie.connect(app, puppeteer);
}
export async function createPupPage(data: {
loadURL: string;
options?: Electron.BrowserWindowConstructorOptions;
}): Promise<Page> {
const window = new BrowserWindow(data.options);
const url = data.loadURL;
await window.loadURL(url);
const page: Page = await pie.getPage(browser, window);
return page;
}

第二周:博客的价值不在于是否被阅读

· 3 min read
阿毛
人生得意须尽欢

大家好,我是一名,跨境行业saas软件开发的前端程序员,阿毛

今年突然想做做博客, 但是我也有点纠结,

  • 一来以前搞过博客,刚开始冲劲很足,到了后面就更新动力不足,慢慢的就荒废了,本来还把数据保留了下来,但是这一荒废都三年多了,以前写的博客数据也删了, 我怕这次也搞个虎头蛇尾就不好了
  • 二来现在年纪也大了,我今年也30岁了,从业也七八年了,现在搞个博客还有必要吗? 写后端,写前端,部署,调试,不纯纯浪费自己精力吗? 关键词是还没人看,有啥意义啊.

基于以上两点,我也考虑了很久要不要再重新整一个,最终让我下定决心的,还是 deepSeek , 我问了 deepSeek , 他给了我很明确的答案, 干,他给我说 博客的价值不在于是否被阅读,而是写作过程对内认知与对潜在机会的触发

说的太好了,那就坚持写呗. 本来想用CSDN来写的, 上周写了一篇,发上去,给老子给气的, 一直审核不通不过,改了好多次,链接什么的全给删了也不给过. 我服了, 算了还是自己搭一个,想写啥就写啥, deepseek不是说了嘛,博客不价值不在于是否被阅读

自己搭的话, 还是写markdown最简单, 别去搞什么前端后端的,搞的太多,精力也分散了,内容就更没有动力去更新了,所以就有了现在这个博客

目前这个博客我是这样想的, 首先要分几个板块

  1. 博客, 这里呢就存每周一至少一篇的博客
  2. 文档, 这里呢就放一些我做的一些小玩意的帮助中心
  3. 笔记, 这里呢就,就吧平时遇到的坑,或者一些总结 记录在这里

大概就是这样, 现在呢,这里的内容还很少, 但是贵在坚持,希望呢,这次我能把这些记录一直坚持下去! 加油吧

第一周:35岁倒计时菜鸟程序员的佛系自救指南

· 5 min read
阿毛
人生得意须尽欢

大家好,我是一名,跨境行业saas软件开发的前端程序员,阿毛

好久没写过博客,以前弄过自己的博客网站,后面也不知不觉就停止了。前段时间突然发现自己的表达能力怎么好像越来越差了,今天突然想,要不还是写写博客? 虽然我知道,可能写了也没几个人看,但总归在互联网上留下了一点我的印记,我给自己定了目标,每周写一篇,一篇不多,我想应该是能坚持下来的,我现在也不想自己去折腾什么博客网站了,感觉废了半天劲,做了也没人看,就自己在看。还不如用别人现成的。

程序员也干了好几年了,算算看,现在这家公司干了第4年了,前面还有三四家公司,虽然都不长,加起来也有七八年了,现在也30岁了,好像技术也不咋的,都说程序员35岁是个坎,好像现在也没几年了。

最近ai也挺火的,好像要吧程序员都给取代了,但是我其实感觉还挺乐观的, 我其实工作中现在ai用的挺多 ,好多代码我都用ai生成,我发现现在生成函数级别的代码,ai真的挺好用, 一个页面的话,ai 生成的代码其实也挺好,但是总感觉还差点意思,需要自己去调整一些细节,要是以项目来说的,现在他也记不了这么多,再发展个几年或许可以。到时候我也正好35岁了,被AI淘汰了,就说, 自己遇到35的人生大坎了 ……

我最近其实在想35岁的时候,我能不能有两款自己的产品?我这个人其实还比较爱倒腾,不能说很喜欢,因为真的也不是那么的喜欢。回想一下,我倒腾过些啥,前几年做了一个vue的表单编辑器, 后面也做了react版本,也没有维护,倒腾了一段时间的个人博客,后面还帮一个 跨境的卖家朋友,做了一个wayfair 的 库存查询插件,前年的时候还做了一个亚马逊的产品对比分析插件, 公司做的插件有个功能是亚马逊的搜索框拓词,我想其他的平台是不是也能拓词呢,于是又做了一个 支持 亚马逊,沃尔玛,Etsy的搜索框拓词插件, 去年国庆节还做了一个多设备共享的计时器,其实做了好些东西,都没有发到网上,就自己自嗨一下,最近想说自己能不能做点真正意义上的产品?所以后面两个我给挂了出来,有兴趣的可以去看看 共享计时器, 拓词插件

写了这么多,也没个中心思想,就是随便写写。反正也没人看,不存在,其实这篇文章,我整个放到deepseek中,叫他帮我润色一下,他润色之后逻辑清晰许多,改变了排版,分了1,2,3,4点来讲,但给我的感觉更像是一篇作文。算了,博客就是要自己写,才有味道。

2024年度的总结与回顾

· 8 min read
阿毛
人生得意须尽欢

大家好,我是一名,跨境行业saas软件开发的前端程序员,阿毛

2024过的好快呀,真的是一转眼的时间就过去了,现在感觉真的是时间过的越来越快了,不知不觉一年就过去了,想当年还在读书的时候,感觉怎么一学期都这么漫长,陈哥让我们做一个年度的总结,我其实好久都没有认认真真的做一个总结了,上次认真的总结我记得还是我,15还是16年我在做销售卖点读机的时候。

这个年度的总结与回顾该写什么内容呢?我觉得应该写一个,我个人的年度总结,而不是我针对我的一年的工作的年度总结,仅仅去写我今年的工作情况。或许我应该写成后者,但是我还是决定按照我自己的方式来写吧,我准备分成工作和生活两部分,今年发生了很多事,很多都让我记忆深刻。我想把他们都写进我的年度总结与回顾中。

生活篇

  1. 我拥有了自己的小孩,其实是去年的事,但是因为是去年年底了,总感觉是今年的事,算了,根据感觉来吧。在以前20岁左右的时候,老觉得小孩很烦人,叽叽喳喳的叫个不停,特别是婴儿的时候,什么吃饭睡觉全要人照顾,这多麻烦呀。等有了自己的孩子才发现,其实真的是一点没错。但是也并不全是,你会发现生命在你呵护中成长的喜悦,他叫爸爸妈妈,他学会走路,你也会发现为什么有那么多人会喜欢小孩,因为真的特别招人喜欢,他会因为你几个简单到甚至愚蠢动作,笑的咯咯咯咯的,快乐真的是会传染的。
  2. 老爸离世。我老爸得癌症已经好几年了,还记得听到这个消息的时候,是公司年中团建,在去青海的路上,初听这个消息,真是感觉天塌了。然后就是返回重庆检察,查出来就是肺癌晚期,多处转移,还有脑转移。后续就是治疗,我爸妈在外做钢筋工,也没有什么保险意识,所以经济压力也给我们家里蒙上一层阴影,这几年大概花了有40多不到50万,我妈也老说,你爸要是不得这场病的话,我们家里的生活将会好很多。也算我老爸厉害坚持了这么些年,这么些年的时间让我慢慢接受这些事实,真正到了我父亲离世的时候,我觉得已经不是那么的不可接受了,可真的到了那一天我还是哭得稀里哗啦的,我父亲的离世,让我真正的明白了,要珍惜当下的时间。
  3. 陈哥给我爸送躺仓。来自陌生人的善意是最温暖的,陈哥不能算陌生人,但是他也没有任何责任和义务来帮助我,陈哥把我叫到旁边的办公室给我说这个事情的时候,我都要哭了,我其实发现我这个人特别爱哭,不对,应该是爱流泪,上次团建,听曾丽娟讲他的小时候的事我也忍不住要流泪,我看 OMG 50滴血极限翻盘的那个视频,我看了好多次,每次都看的想流泪。我觉得我是被感动的,如果一件事和我产生共鸣或是真正的打动了我,我想我会忍不住流泪的。 这可能和我在公司以往的形象不符,但是事实就是这样。

工作篇

今年提交了一些代码做了一些功能,比如 做了广告生成仪,对接了卖家精灵,关键词挖掘,反查,词库产品库等等,我特意去gitee了看了看最近一年的提交量,最近一年贡献:1667 次,最长连续贡献:27 日,也不知道是多是少。 alt text

对于我的工作,我觉得我能力并不出众,甚至可以说是平庸,唯一一点可能比较好的是,我还比较爱折腾,我根据我的理解做了一个市场分析的插件,我还在国庆节做了一个共享的计时器,年终开会的时候我觉得可以用用,提醒演讲的人现在所用的时间,防止大家演讲超时。 工作中一直有个烦恼,因为以前写了很多垃圾代码,可能有对业务理解不够,可能是能力问题,也可能需求变化等,现在能力些许提升,觉得有更好的实现方式,就想去改,就想去重新实现一遍,但是呢以前其实有很多细节的处理和坑,重新去实现呢,就特别容易出问题,不改心里不舒服,而且后续的维护也更耗时,改了容易出问题,整的很烦躁。反思一下,今年写代码,最好还是先多想,想清楚了来再写,尽量少些垃圾代码,但是也不好说,或许我现在觉得很好的方案,以后也变成垃圾了也不一定。

关于明年的计划,优麦云方面,只能说我们还是要跟着产品的规划走,如果可能话,我还是特别想做优麦云的客户端软件然后逐步的替代掉插件。我个人方面的话,我喜欢折腾,能不能自己折腾一个超过1000人使用软件呢,这些应该只能算是目标吧,不能算是计划。

写到这里,你说我总结了个啥呢?好像啥也没有总结,全是回顾,只能说回顾亦是总结,我这个人文采不太好,不太会总结这些,说话一紧张容易冒汗,我就想到哪儿,就写到哪儿吧,总归比不写要强吧。