主页

想做一个线上待办清单引发的思考 - Node开发

启动服务 打开VS 久违的动作 幸好自己还没有忘记

领导有个习惯,每次都会把部门的待办事项用excel列出来,然后邮件发送给下属并抄送给上级,便于跟进工作事项,任务列表一更改然后再发送一遍邮件,这种管理方式没什么问题,但是这种操作方式实在是低效。

我决定做一个简单的线上待办清单,领导添加待办事项,下属可以更改状态,还有一个最关键的功能就是发送邮件功能,一键发送待办清单给下属并抄送上级领导,在传统企业里邮件真是必不可少的。

1. 数据库准备

动手开发前先把数据库创建了,由于上次学习了ORM模块,不用再在数据库里操作SQL语句了,直接上代码写上数据表的结构以及一些初始数据的导入代码。

2. 前端页面折腾

数据库结构搞定之后,开始折腾前端页面的设计,也不想重新写页面了,直接copy之前项目的代码,短短半个小时,前端页面就搞定了,如下图:「PS. 结果后面又调了两天,醉了」

前端表格使用的bootstrap table制作,与后台数据库的交互直接使用Ajax异步处理,现在先编写获取数据的API,简单如下:

// find: 获取table的数据
router.get('/bootstrapTable', function (req, res, next) {
  todolist.findAll({
    order: [['id', 'desc']]
  }).then(function (r) {
    res.send(r);
  });
});

一并写完增删改查,前台页面就可以简单的调用API就能实现一些功能了,例如添加列表功能,更改列表以及删除列表。

3. 清单编辑功能

最近几次开发都是使用Bootstrap Table来展现列表,这块也是最折腾时间的地方,每次写这个表格,总是有一堆奇奇怪怪的想法想要去实现,没有一个整体的规划,功能来回调整,于是在这上面浪费很多时间。这次主要折腾了字段编辑功能,以及更改列表功能。

更改表单的功能有两种方式:一是使用modal弹出表单的方式;另一种是行内编辑的方式;modal弹出表单的方式会添加大量的js脚本,后期管理起来非常的不方便。而行内编辑的方式,虽然不用写大量的代码,但是功能上就比较单一了。

总体来说,两种方式都不是挺理想,我觉得我应该学习一些新的技术了,例如Vue。后来还是选择了modal弹出编辑的方式,功能做了一半,我突然就想,为什么要有更改功能呢?,总是用开发者的思维去做产品肯定不行,开发者认为增删改查是最基本的功能点,而用户在用产品的时候,其实并不一样,用户关心的是功能点,我做这个产品,面对的用户是谁?我得好好想想再动手……

4. 邮件功能

起初想着,在每条列表的后面加上一个操作功能-发邮件,使用简单的mailto:lupeng@xxx.com链接,来触发系统默认邮件客户端来发送邮件。

后来仔细考虑了一下实际使用场景,放弃了这种方式,平常使用的时候,基本上都是表格所有的内容一并发送,来达到提醒的作用,而非督促完成每一条任务清单。另外,发送邮件最好能真正意义上的一键发送,需要省掉中间弹出邮件客户端的环节。

想明白实际的使用场景后,那么邮件的功能就需要更深入一点,需要引入邮件模块,取代使用客户端的作用。

开发过程中的一些想法,作参考,希望能给你一些启示,项目地址:https://github.com/pengloo53/info

阅读更多

每天1个俯卧撑,这样也行?《微习惯》的力量

[1]

我一直都比较喜欢给自己定计划,坚持一些我觉得应该坚持的事情,比如跑步,比如读书,比如coding,还比如练英文。然而理想一直比较丰满,现实总是很残酷,每次通过突然的「头脑发热」制定出来的坚持计划,总是在经历1周,2周,3周后,就因为某天的某个原因突然就停止了。

这个突然的「头脑发热」被作者称作为「动力」,由于某天的某个原因没有坚持下去,是因为「动力是不可靠的」。我们不能总是去依靠动力达成一项目标。「激发动力」的策略教我们依赖这些东西:励志视频、文章、给自己打气的话。作者认为这种方式非常不可取,每个人都会有不在状态的时候,生病了根本不想coding,外边下雨了,没法外出跑步了。如果一周都不在状态,那么依靠动力的方式显然就不尽如人意,最终会使你的习惯早早流产。

动力不可靠,我们不能依靠它充当建立习惯的策略。

[2]

我们在制定习惯的时候,总是按照心中理想的标准去制定,例如:我要每天学习英语1小时,每天读书1小时。因为人们都希望能更快的看到成果,所以我们的目标一般制定得都比较高,前两天由于动力驱使可能能够完成既定目标,可是越到后面越难以维持目标的达成,渐渐没了信心,最后干脆放任自流而放弃了。

在作者看来,每天依靠自己的意志力跟自己对抗,这是一个自我损耗的过程。作者指出意志力损耗的五大因素为:努力程度、感知难度、消极情绪、主观疲劳和血糖水平。举个简单的例子,一个把目标制定为每天1个俯卧撑,一个给自己制定每天锻炼半小时。假设两人意志力一样,那么后者坚持的时间将会更短,因为它损耗的意志力更多。当意志力耗尽的时候,也就是你放弃之时。

意志力虽然可靠,但它的资源是有限的。

[3]

作者提出使用微习惯+意志力的最佳组合。微习惯关键体现在「微」字上,正因为它的目标小,根本不需要多大的努力就能达成目标,损耗的意志力基本为0,一旦你开始了,最后你会惊叹自己竟然超出目标完成任务,而给予自己更大的鼓励和信心。

万事开头难,而恰巧微习惯的策略就是让你的开头不那么难。可能这时你会疑惑,假设我每天只做一个俯卧撑,那么给我带来的锻炼微乎其微,又有什么用呢?不要质疑这点,因为它所产生的作用正是微习惯最大的魅力,我被这种魅力感染到了。

我是一个缺乏动力,而且意志力也不够强的人。人生坚持最最长的事情就是曾经坚持跑步了3个月(中间并非连续),当时一直是某个动力撑着我,最后也因为动力消失,意志力耗尽而终止了。自从选择了微习惯策略后,发现坚持一件事情真的没有那么困难了,微习惯的作用就是让你在坚持某件事情的时候,没有那么多抵触的情绪(意志力损耗),比如,像每天吃饭睡觉一样去坚持锻炼。

这是我坚持keep4周的截图,一天也没有断过,而我给自己设置的目标,并非是上面写的每天10分钟。那我的目标是?我说出来你可能都不会相信,我给自己设置的目标是「饭后下楼去操场」,也就是说每天我只要下楼到了操场,我的目标就达成了,而正如你看到的,我几乎每天都超额完成了我的目标,因为我发现,我都已经到操场了,看到那么多人在运动,我何不待会再走。就这样,如你所见,我每天至少坚持了10分钟的运动,如果我将目标设置为每天运动10分钟,我相信不会有这样的成果。我之前设置过每天20个俯卧撑的目标,还是在某天动力不足,状态不佳的时候断送了,再拾起时,心里就开始破罐破摔了。

而「每天下楼去操场」几乎是不可能失败的目标,如果你觉得这个都很难达到,可以尝试把目标定得更小,「每天铺上瑜伽垫」「每天到家后再下楼」等等,只要铺上瑜伽垫,目标就算达成了。不用担心这么小的目标有什么意义,能有什么成果,这不是自欺欺人嘛。我想说的是,只要你有一颗上进的心,试试就知道了,会产生意想不到的成果,由于我每天下楼去操场,我不仅运动远远超过10分钟,甚至在这段时间,将我之前在「得到app」以及其他平台上买的一些课程都听完了,想想却是不可思议。

有时我再想,现在我每天的运动量,远远比我之前设置的每天20个俯卧撑要多得多,而后者竟然没有坚持下去,前者竟然一天没落下坚持了1个月。正是因为「每天饭后去操场」这个目标实在是微小得你不可能失败。

作者在书中也花了大量的篇幅介绍大脑的工作原理,以及动力、意志力和习惯的一些理论和实验,这些观念让我耳目一新,推荐大家读一读。

阅读更多

原来卡耐基是一名被作家耽误了的伟大推销员

【1】 人性本能就是懒惰的,思想更是如此,在某个岗位待得越久就越不想动弹,得过且过,听到太多的人抱怨着自己的工作,每天干着自己不想做的事情。其实很多时候并不是他们不能换其他工作,而是人的本能驱使不愿意去尝试改变罢了。

总是找诸多借口:万一换了个工作,换了个岗位,依旧不是自己喜欢的呢,万一还不如这个了呢?可是,你连尝试都没有去做,又如何知道适合不适合,喜欢不喜欢呢。想想好麻烦,我到底想要做什么?还是先这么待着吧。

【2】 今天翻开卡耐基《语言的突破》这本书,习惯性的从头开始看,看到卡耐基的简介。卡耐基被誉为20世纪最伟大的人生导师,相信不少人都看过他的代表作《人性的优点》《人性的弱点》。他生于1888年,出生在贫苦农民家庭,从小也就是在农村帮父母打杂干农活,一年的辛勤劳作可能只是因为自然灾害,所有的成果就会付诸东流。他发誓自己绝不要这样的生活。

高中毕业后就读一所师范学院,由于家境过于贫穷,他不得不出去打工以赚取生活学习等费用,他非常自卑,他想寻求出人头地的捷径。当时在学校里最具名望的,一类是运动员,一类是辩论演讲获胜的人。他选择了辩论演讲,一次又一次的失败使他更加的灰心和绝望。

毕业后本可回家乡当老师,但是他却选择前往学校总部为该校做推销员,尽了最大的努力,但是并不是太成功,于是又改推销肉类产品。渐渐推销成绩越来越好,从区域25名跃升为第1名,但他却拒绝了晋升经理的岗位,跑到纽约当了一名演员,干了一年后,他断定演员这行没有前途,于是他又改回推销本行,在一家汽车公司推销汽车。

他知道,推销员并不是他的理想。他很纠结,如果放弃现在的工作,能有什么能力养活自己呢?一边是现实,一边是理想。其实我们很多人都存在于这种状态「我不喜欢我现在的工作,可是我能去哪呢」。

在推销汽车的某天,遇到一个老者,他和老者的一些对话,让他在某个晚上坚定了自己想成为一个作家的理想。于是他放弃了推销工作,去应聘成为了一名讲授商务技巧的老师,从教授学员中渐渐找到,对于如何帮助学员克服恐惧的独特方法,对于人性的一些理解……

【3】 看完卡耐基的简介,是不是觉得他最开始的人生经历,其实和我们大部分人都很类似,很多时候我们同样是在现实和理想中纠结,我们纠结过后,不敢或是不愿去做出改变,我们总是选择放弃理想 ,接受现实。但是他却勇于去尝试,参加辩论演讲,去推销,当演员,做老师,最后成为了一名伟大的作家。回头想想,我觉得挺戏剧的,再怎么看「推销员」「演员」这些工作都跟「作家」扯不上关系啊。

很多时候,你并不知道你到底想要什么,只能去不停的尝试,也许在某个岗位上受某个人的影响,你突然就发现了自己到底想要的是什么。所以问题的关键还是你的接触面太窄了。

很多事情,不要停止尝试,不去尝试怎么知道你喜不喜欢呢

阅读更多

《苹果三剑客》之我见

2018年读完了第一册书籍《苹果三剑客》,共三本:《乔布斯传》《沃兹传》《乔纳森传》。

1.《乔布斯传》

《乔布斯传》之前读过一遍,这次重新拾起来也是为了再次领略一次他的风采,他是苹果的创始人兼灵魂人物,初次了解的时候,我被他过于优秀的战绩冲昏头脑,满心的崇拜,沉醉于他所谓的现实扭曲力场中。这回再次阅读《乔布斯传》后,我却感到有一丝丝的悲哀。

出生就被亲生父母抛弃,天生缺乏人情冷暖的感知,与亲生女儿lisa的情感纠结,饮食习惯的怪异,对产品设计的痴迷(得癌症躺在病床上,就因为医疗设施设计得太难看了而拒绝使用),近乎变态的为人处事风格,或是说现实扭曲能力,不仅扭曲了他人,还扭曲了自己,使自己相信能够战胜癌症,而不用治疗。

如果剥离他的成就,这样的人在我们看来,简直就是神经病,完全不能当作一个正常的人去相处。再次读完《乔布斯传》的时候,整个人的心情都是凝重的,他的经历确实传奇,而我们只能当成是一种传奇,无法效仿。

或许他们是别人眼中的疯子,但他们却是我们眼中的天才。因为只有那些疯狂到以为自己能改变世界的人,才能真正改变世界。

2.《沃兹传》

读《沃兹传》时的心情,跟读《乔布斯传》完全不一样,这本书是沃兹本人撰写的自传,读起来如其人一般,轻松快乐有趣。沃兹是苹果公司的头号人物,与乔布斯一同创建的苹果公司,苹果公司的主要产品-苹果电脑,它的始祖Apple IApple II是沃兹一人一手打造的,他可以称作是苹果电脑之父。

沃兹的天才在我们周围的生活中其实比较常见的,每个领域都会出现这样的天才,他精通于电子,正好是PC时代所必需的。他生性羞涩,与很多发明家一般,精通于那个领域,活在自己的世界里。他相信最好的产品都是出自某一个人的手中,独立产生的。他不擅长与人沟通交际,他也从不相信好的发明能够出自某个团体或是某个委员会的群体决策中,现实也确实如此,某个领域伟大产品的出现均是出自某一两个人,比如计算机语言C,Java等的诞生。当然这个需要你足够优秀才行得通,他就是那个时代足够优秀的人。

如果是奔着了解苹果公司而去看这本书,那么可能会让你失望了,因为沃兹在苹果公司的时间并不长,在苹果公司上市后不久就因为一场事故部分失忆而离开了苹果公司,他并没有经历苹果公司的堕落,也没有经历乔布斯的回归,更没有经历苹果公司的崛起一举成为市值最高的科技公司。但是,他却因为苹果公司而一举成为亿万富翁。对于他离开苹果后的工作生活,我只能用四个字来评价他:「有钱任性」。斥巨资办音乐会,赔的一塌糊涂,无所谓,用他的话说就是:「是否赚到钱的确很重要,但是举办一场好的演唱会更重要」。

相信大部分工程师都期望能有这样的经历,凭借自己的本事,一举成名,从此笑傲江湖,富成一个「废物」。

3.《乔纳森传》

乔纳森是苹果公司的首席设计师,目前在苹果公司上拥有无上权利,虽然职位上比CEO库克要低,但乔布斯在世的时候公开表达过,除了他自己,乔纳森可以不用听任何人的指挥。

乔纳森来自英国,从小就表现出天才般的设计天赋,其实我并不相信什么天才理论,他和沃兹一样从小就受家庭因素的影响,有一位给他们指引人生的好父亲,父亲对他设计方面的培养贯穿了他的整个童年。当然这所有的功劳,一定离不开他本人对设计的热爱和痴迷,对设计的这份执着和坚持才能使他功成名就。

在学校就已经出名的他,首先就被韦弗集团的董事长看上,接受了韦弗集团的资助完成学业,毕业后,才华横溢的他拒绝了许多优秀公司抛出的「橄榄枝」,遵守了他对韦弗集团的诺言,入职了韦弗集团,担任一名设计师,结果也不出意外,很快一有机会就离开了韦弗集团,天才更加需要的是能挖掘天分的伯乐。后来朋友邀请他加入新创立的小设计公司 -「橘子设计」,因为这个公司,他最终接触到了苹果的项目,进而对工业设计产生了浓厚的兴趣,他初到苹果公司时,正是苹果没落的时候,再优秀的人才,也忍受不了拙劣的企业文化,没来多久他就开始渐渐厌倦,直到乔布斯(他的伯乐)的回归。

后面的事情大家就比较清楚了,乔纳森包揽了苹果所有的产品的设计,iMac,iPhone,iPad,Macbook,开启了苹果卓越的工业设计,使苹果成为一家以设计主导的公司,乔布斯走后,苹果公司一次内部调整,乔纳森除了产品的工业设计外,同时还负责了软件界面的设计工作,从iOS 7开始摒弃了拟物设计,这次他开创了全民扁平化设计时代。

乔纳森在苹果公司能有如今这样的成就,可以说是乔布斯一手促成的。正如他自己在乔布斯追悼会上所说的:

在许多其他的公司里,伟大的想法和设计往往在创作过程中就迷失了。如果不是乔布斯一直支持着我们,跟我们一起工作,冲破层层阻力让我们的想法变成产品,那么我和整个团队的想法就完全没有意义,也没有用武之地。

4. 读书之我见

看完《苹果三剑客》,给我印象最深的人还是乔布斯。乔布斯本人的人生经历就是一个传奇,很难再找到如他一般的人物,沃兹和乔纳森再优秀,如果没有乔布斯这样的伯乐,远远不能达到如今这般的名气。这仅仅是我个人的观点。

我一直认为,是乔布斯成就了苹果公司,而苹果公司成就了沃兹和乔纳森。好多人认为在苹果创立之初,沃兹负责产品技术,而乔布斯负责营销,两个人相辅相成,成就了苹果公司,谁也不能离开了谁。我并不认同这样的观点,在我看来,乔布斯离开了沃兹,日后照样能取得耀眼的成就,而沃兹离开了乔布斯,就不一定能有如今的成就,乔纳森也如此一般。当然我并没有否定沃兹和乔纳森的才华,只是天才是需要被挖掘的,而乔布斯就是那个挖掘天才的人。

阅读更多

日志 - Node实战

express模块简单集成了一个日志模块morgan,可以将请求的一些消息打印在后台终端上,然而在实际的生产系统中,我们通常需要更完备的日志功能,以便供运维人员定期查看。

这里简单介绍winston模块的引入,实现最简单的日志写入文件功能,首先项目中安装模块,如下命令:

npm install --save express-winston
npm install --save winston

然后在项目app.js文件中引入对应的模块,如下代码所示:

var winston = require('winston');
var expressWinston = require('express-winston');
// 正常请求的日志
app.use(expressWinston.logger({
  transports: [
    new (winston.transports.Console)({
        json: true,
        colorize: true
    }),
    new winston.transports.File({
      filename: 'logs/success.log'
    })
  ]
}));
// 正常访问路由
routes(app);
// 错误请求的日志
app.use(expressWinston.errorLogger({
  transports: [
    new winston.transports.Console({
        json: true,
        colorize: true
    }),
    new winston.transports.File({
      filename: 'logs/error.log'
    })
  ]
}));

日志文件分为success.logerror.log,放在正常路由之前则为成功日志,放在正常访问路由之后,则为错误日志。如不需过多功能,这样放进项目里即可,详细了解可查看官方文档: winstonjs/winston: A logger for just about everything.

阅读更多

给自己做一个SWOT分析

最近一段时间在给领导写年终总结报告,领导要求要用《SWOT分析法》来描述这一年的工作不足以及改善对策。

以前写这块内容的时候,我通常都是使用列举法,将内容一条条的列出来,然后针对每个问题,做简单介绍以及改善对策,down个模板,填下内容,整齐的排列出来,看起来还算不错。

在听领导说到要用SWOT的分析法来写这块内容的时候,起初我是抵触的,又得改报告,好不容易憋出来的内容以及花大量时间调整的格式,又付之一炬了。

反正,这一页得重写了。于是花了点时间,简单了解了一下什么是SWOT分析法,然后将大致的内容通过这种分析方法填补进去,顿时感觉内容不仅逻辑清晰了,也似乎显得有意义了。

什么是SWOT?

SWOT分析法(也称TOWS分析法、道斯矩阵)即态势分析法,20世纪80年代初由美国旧金山大学的管理学教授韦里克提出,经常被用于企业战略制定竞争对手分析等场合。

这是MBA的一种方法论,以前对方法论这种东西总是不屑一顾,总觉得似乎有些空大,没什么实际作用。这很有可能是因为自己站的高度不够,很多问题的分析还压根用不上什么方法论这些高端的概念。但是简单了解一下,总归是好的。

S代表优势(Strengths),W代表劣势(Weaknesses),O代表机会(Opportunities),T代表威胁(Threats)或风险。优劣势分析主要是着眼于企业自身的实力及其与竞争对手的比较,而机会和威胁分析将注意力放在外部环境的变化及对企业的可能影响上 。在分析时,应把所有的内部因素集中在一起,然后用外部的力量来对这些因素进行评估。

那么知道了这个方法论的关键点,再设身处地的思考一下,不足分析与改善。你所分析的问题内部因素有哪些(优势和劣势)?外部因素又有哪些(机会和风险)?画出象限图如下:

再把之前列举的那些123456内容往象限图里一套,你会发现内容从简单的列表顿时上升的一个高度,从象限图中能看出一些逻辑。但还是没有达到分析的效果,接下来的内容才是这个方法论最关键的地方。

我们已经列出了优势,劣势,机会以及风险,那么接下来的问题就是如何去应对,制定出实际可实施的战略,这个才是最精彩的地方。我们将4个象限拓展,变成8个象限,如下图所示:

针对优势和机会,我们要如何利用?这是SO战略;针对劣势和机会,我们要怎么改进?这是WO战略;针对优势和风险,我们要如何管控?这是ST战略;针对劣势和风险,我们要如何消除?这是WT战略。

当你填完表格后,对于你要分析的问题将会有个非常清晰的思路。本来很乱的一些想法,似乎感觉明朗了。这可能就是方法论的作用吧。以下是网上的一个小例子。

来分析一下自己吧

SWOT分析法通常用于企业战略制定以及竞争对手分析,但是我觉得用这种方法来分析一下自己也是可行的。因为通常情况下,你并非很了解你自己,通过这个方式可以客观的认识一下自己。

这里就以我自己为例,使用SWOT分析法对自己再做一个客观全面的了解,分析如下:

同样,当你在做一些问题分析的时候,尝试一下SWOT分析法。没准会产生一些惊喜哦。

参考文档:

阅读更多

Bootstrap-Table初使用

温故而知新。学习使用Bootstrap Table已经完整的完成了一个项目,这里还是简单对Bootstrap-Table的使用做一个简单的介绍以及实例的演示。

什么是Bootstrap Table,自行查看官网介绍。刚接触可能一头雾水,建议直接从官方文档的开始使用开始看,后面再看一些例子,最后详细读文档部分,学习使用它,自定义一些自己想要实现的功能。

最开始使用Bootstrap Table的原因是做后台数据管理使用。后台的一些业务数据习惯通过表格的形式展现出来,以便于做一些增删改查的操作。如果有一个通用的模块直接能在前台渲染出表格,服务器端只需要传输基础数据就可以了,那就太方便了。于是就找到了Bootstrap Table

1. 引入文件

首先要引入Bootstrap Table的相关文件,下载源码引入或者直接引入CDNJS提供的外链地址,不过建议还是下载源码,源码文件结构如下:

bootstrap-table/
├── dist/
│   ├── extensions/
│   ├── locale/
│   ├── bootstrap-table.css
│   └── bootstrap-table.js
├── docs/
└── src/
    ├── extensions/
    ├── locale/
    ├── bootstrap-table.css
    └── bootstrap-table.js

引入dist目录下的bootstrap-table.css以及bootstrap-table.js,如果使用中文,还要应用locale/bootstrap-table-zh-CN.js注意每个文件均提供了min版本以及正常版本,建议在开发测试阶段引入正常版本,便于调试。

当然最后不要忘了引入bootstrap以及jQuery的文件。最后在页面head部分引入css文件如下:

<link rel="stylesheet" href="/bootstrap/dist/css/bootstrap.css">
<link rel="stylesheet" href="/bootstrap-table/dist/bootstrap-table.css">

在页面body最后引入js文件如下:(注意:1. 顺序不要乱;2. 根目录依据自己项目而定)

<script src="/jquery/dist/jquery.js"></script>
<script src="/bootstrap/dist/js/bootstrap.js"></script>
<script src="/bootstrap-table/dist/bootstrap-table.js"></script>
<script src="/bootstrap-table/dist/locale/bootstrap-table-zh-CN.js"></script>

2. 使用方式介绍

根据官方文档介绍,使用方式有两种,一种:通过 data 属性的方式;另一种:通过 JavaScript 的方式。说白了就是把控制代码写在HTML里还是写在JS里。在实际项目的开发中,大多数是将控制代码写入JS里,这样更方便灵活,数据通过ajax异步请求的方式获取,数据格式为json。所以下面我就介绍最后这一种的实现方式。也就是官方提供的这段示例代码:

$('#table').bootstrapTable({
    url: 'data1.json',
    columns: [{
        field: 'id',
        title: 'Item ID'
    }, {
        field: 'name',
        title: 'Item Name'
    }, {
        field: 'price',
        title: 'Item Price'
    }, ]
});

3. 具体功能具体分析

官方文档的开始使用部分基本上就上面那些内容。接下来就是文档部分了,该部分详细的讲解了Bootstrap table每个参数每个方法事件的使用。

这里我不准备按照官方参数说明一个一个来叙述,那样没有什么效果,因为官方文档已经做了简要介绍,再啰嗦一遍不会用还是不会用。所以这里以我项目里实际的例子来叙述,后台使用的是Node.js作为服务端。

3.1 请求获取json数据

前面说了使用Bootstrap table有两种方式,一种是把代码写在html里,一种是把代码写在js里。这里的示例都是采用第二种方式(下面就不再贴出HTML的代码里)。HTML里的代码就这么一行,如下:

<table id="table"></table>

table的数据都是从后台异步获取,这也是最常用的一种方式,通常在项目开发中,数据基本上是来自后台。下面看一段js代码:

$('#table').bootstrapTable({
      url: '/admin/staff/ajax/table',
      height: 550,
      toolbar: '#toolbar',
      search: true,
      showRefresh: true,
      showExport: true,
      ajaxOptions: {global: false},
      pagination: true,
      sidePagination: 'client',
      pageNumber: 1,
      pageSize: 10,
      pageList: '[10, 20, 50, ALL]',
      sortOrder: 'desc',
      sortName: 'uid',
      columns: [{
        field: 'uid',
        title: 'id',
        visible: false
      }, {
        field: 'userid',
        title: '员工号'
      }, {
        field: 'username',
        title: '姓名'
      }, {
        field: 'department',
        title: '部门'
      }, {
        field: 'office',
        title: '科室'
      }, {
        field: 'produce',
        title: '工序'
      }, {
        field: 'team',
        title: '班组'
      }, {
        field: 'operate',
        title: '操作',
        align: 'center',
        valign: 'middle',
        events: operateEvents,
        formatter: operateFormatter
      }]
    });

上面是我一个练手项目的实际代码,功能是对员工信息的一个处理。官方文档里分为表格参数和列参数。上面代码中例如url,height等是表格参数,其中表格参数columns的值是一个数组,数组里每个元素都是一个对象,对象里的一些参数属于列参数。具体参数有哪些,大致功能是什么查看文档即可。

其中url表格参数定义的是异步请求的地址,例如上面/admin/staff/ajax/table意思就是要从这个地址来获取表格所需要的json数据。那么现在来看看后台取到的数据格式。由于后台使用Node,那么又是一段js代码如下:

// 人员管理-ajax返回bootstrap-table数据
router.get('/admin/staff/ajax/table', function (req, res, next) {
  var adminid = req.session.adminInfo.adminid;
  dbSelect.getUsersByAdminNoPage(adminid, function (err, rows, fields) {
    if (!err) {
      res.json(rows);
    } else {
      errHandle(res, 'db return err', err);
    }
  });
});

后台代码可以不用太关心,因为不同的编程语言后台实现是不一样的。直接看下返回的数据格式:

[{
    "uid": 181,
    "userid": "1000000",
    "username": "赵彦飞",
    "department": "Cell制造部",
    "office": "Cell检测科",
    "produce": "Q Boxing",
    "team": "A"
},{
    "uid": 257,
    "userid": "盛雪增",
    "username": "1820",
    "department": "Cell制造部",
    "office": "Cell检测科",
    "produce": "Q Boxing",
    "team": "A"
}]

返回的数据是个数组,每一个对象对应一行数据,字段名对应列参数里的field,都匹配上了,那么数据就能显示出来。最终效果如下:

3.2 操作功能(修改&删除)

可能你会发现,列参数里最后一列的操作是从哪里来的,返回的json里并不存在这个数据,点击之后需要有一些数据处理的操作。弄明白这个需要了解eventsformatter两个列参数的用法。

formatter是格式化表格数据的一个参数,返回一个function,还是上面那个表格,定义一个operateFormatter函数,如下:

function operateFormatter(value, row, index) {
    return [
      '<a class="op" href="javascript:void(0)" title="修改">',
      '<i class="glyphicon glyphicon-pencil text-primary"></i></a>  ',
      '<a class="op" href="javascript:void(0)" title="删除">',
      '<i class="glyphicon glyphicon-trash text-danger"></i></a>'
    ].join('');
  }

当然你可以把函数直接写在列参数下。函数的意思就是直接返回两个链接当作operate这个field的值。有了样式,那么点击动作同样需要定义,那么参数events就起作用了,代码如下:

window.operateEvents = {
    'click [title=修改]': function (e, value, row, index) {
      alert('编辑功能暂不开放');
    },
    'click [title=删除]': function (e, value, row, index) {
      $('#delModal').modal('show');
      clickId = row.uid;
    }
  };

3.3 分页功能

当表格数据比较多时,那么就会用到分页的功能,分页分为前台分页和后台分页。什么是前台分页?什么是后台分页?前台分页指的是一次性加载全部的数据到客户端,然后进行分页;后台分页指的是分页请求服务器资源。这两种分页方式各有利弊,不多介绍,这里给个参考值,数据量不上万,建议使用前台分页,一次性加载完毕,其他操作就是前台处理了。

确定使用什么类型分类首先定义表格参数sidePagination,不设置的话,默认值是client,也就是前台分页模式;如果设置为server就是后台分页模式。

我自己写的项目里目前均是通过前台分页的模式来实现的,最初的考虑是前台一次性加载所需的数据保存在浏览器端更便于前台的一些操作,翻页和浏览的过程中也无需再向服务器端请求了。这种方式实现起来,后台以及数据库请求的代码逻辑较简单。

pageNumber: 1,
pageSize: 10,
pageList: '[10, 20, 50, ALL]',
pagination: true,
paginationLoopz: true

这些表格参数是控制分页的,详情翻翻文档,不难理解,显示出来的样式如下图:

3.4 自动分页功能

分页很简单,样式功能基本上都定义好了,只要使用对应的表格参数即可。那么如何让它自动翻页呢?因为在做这个项目的时候,接到一个前台需求,那就是表格数据直接放在大厅屏幕上,上面的数据需要轮回的滚动,这样就没有了人去点击下一页了。

表格数据怎么自动滚动呢?如果把人为去点的动作,直接设置成自动点击就可以了。于是写个function如下:

// 定时翻页
function changePage(){
    $pageNext.click();
}
setInterval('changePage()', 1000*3);

改变页面,用JQuery定义下一页按钮,每隔3秒执行一下click函数就可以了。还有一个问题就是我们要在表格加载完成之后,才能去定义$pageNext这个元素,所以还要使用一个表格事件才能生效,如下代码:

$table.on('post-body.bs.table',function(){
    $pageNext = $('.page-next');
});

post-body.bs.table这个事件就是渲染完成之后触发的(Fires after the table body is rendered and available in the DOM),这个时候再合适不过了。

3.5 数据预处理自定义

数据预处理指的是在从服务器处取得原始数据后,我们提前先进行加工处理,然后渲染到前台table中。我自己最常用的一个功能就是给数据添加编号,就像每次在Excel中总是喜欢在最前面一列加上编号1,2,3,4,5…

这里就用这个例子来展示一下实现方式,数据预处理我们要用到responseHandler这个表格参数。

responseHandler: function(res) {
    for (var i = 0; i < res.length; i++) {
        res[i].rid = i + 1;
    }
    return res;
},

输入一个参数res,也就是服务器返回的那个对象,处理完后也返回res这个对象,通常情况下,res是个数组,数组元素是对象,所以上面代码就是在每个数组中每个对象的前面加上一个字段rid,rid从1开始累加,就是编号了。 如下图所示:

3.6 表格数据自定义

看到上图表格,优先级字段那块显示的1234,是不是觉得还挺酷的,怎么实现的呢?从上面了解的情况,我们知道,表格的数据都是来源于后台的数据表,而数据表中存储的都是原始数据,是不带样式的,而表格中如果想要显示一些带样式的数据,需要用到列参数的formatter参数。

优先级这块,后台直接储存的是[重要紧急,重要不紧急,不重要紧急,不重要不紧急] 四类,而这里我用1,2,3,4来替代了。使用formatter参数如下代码:

formatter: function(value, row, index) {
    var msg = '';
    switch (value) {
        case '重要紧急':
            msg = '<lable class="label label-danger" title="' + value + '">1</lable>';
            break;
        case '重要不紧急':
            msg = '<lable class="label label-primary" title="' + value + '">2</lable>';
            break;
        case '不重要紧急':
            msg = '<lable class="label label-warning" title="' + value + '">3</lable>';
            break;
        case '不重要不紧急':
            msg = '<lable class="label label-success" title="' + value + '">4</lable>';
            break;
    }
    return msg;
}

注意这是列参数,而非表格参数,每一列都可以使用它自定义显示样式。

3.7 详细展开功能

上面介绍了表格数据自定义功能,它是一个列参数,可以表格数据的样式。这里介绍一个表格参数,针对整个表格有效的格式化功能。如下图所示,每一列前面都有个加号用来展开详细信息。

那就是参数detailViewdetailFormatter的作用,简单设置这两个参数如下所示:

detailView: true,
detailFormatter: function () {
    return 'somethings';
},

很好理解,第一个参数打开详细展开视图,也就是前面会多一个加号;第二个参数是格式化详细展开的内容,这里返回somethings字符串,那么每一行点开都是显示somethings的字样,如下图所示:

大概了解了这块功能,现在我们实现一个实际的需求。如果后台要显示的字段很多,全部在前台表格中显示会显得太拥挤,也没有主次,于是可以考虑将一部分次要内容放在详细展开这里显示,比如一些备注信息等等。

参考:

阅读更多

我的2017总结

个人对我的2017年总体不太满意,本来想放弃去写这样的一篇总结,但是看到别人都在总结,觉得不管得失,总结一下总归是好的,所以还是挣扎着写完了。

生活:

生活看似不平凡,实则没有多大的惊喜。看似不平凡的是,这一年我买车买房了。1月份的时候买了车,结束了班车地铁的通勤生活,走上了每周定期办理进京证的日子。买车给生活带来便利的同时,也带来了一些负面因素,每况愈下的通勤交通让我不再有耐心,浮躁了不少。

年中考虑买房,从看第一套房到签约,总共不超过两周时间。就这么快的定了,并不是手上的钱够了,而是觉得北京房地产这个时间正适合,担心再不入手,怕以后没有机会了。时间刚好这么巧,2018年1月正式开始还贷,2018是我的房奴元年。

这一年虽然搞定了房子车子,但是这些事情都是: 时间到了,自然就有了,并没有多大的意外和惊喜。希望2018年能主动创造一些惊喜。

工作:

工作上看似取得一些成就,实则内心很矛盾。这一年我升职了,而且升职的跨度似乎有点大,公司换了,工作地点换了,工作内容换了,甚至是工作思维都给换了,俗称被「洗脑」了。与其用「换」字,倒不如用「颠覆」一词可能更合适点。

各种不适应随之而来,从最开始听到要升职消息时的忐忑不安,到激动,到换工作的新鲜,再到对新工作内容的热情,到自豪,再到思维理念不一致的反感,到抵触,到冷漠,最后到现在的归于平静。这个过程走得却是有些艰辛,甚至是痛苦。

有时我会想,甚至给自己标榜「工作中,如果你在一段时间内觉得很不适应,累,烦躁,那么,坚持住,坚持过去了,你就成长了。相反,如果有一段时间,工作特别轻松,没什么挑战,那么,你该注意了,自己是不是处在混吃等死的状态。」,而现在我想补充一点「如果长期处在烦躁的状态,那么应该考虑一下合适不合适的问题了」。直到现在,我依然不是很确定,这次升职给我带来的影响是否是正向的。这个问题的答案通常要等到多年以后才能知晓,但到那时可能就有些晚了。

学习:

在学习方面,2017年可算是悲惨至极,没读几本书,没学什么技术,也没写几篇文章。相比2016年,2017可以说是完败。这也是为什么我对自己的2017非常不满意的原因。如果工作和生活方面都算是加分项的话,那么学习方面一下就把分数拉到了负数。

出现这种情况,跟上述生活&工作发生的变化有着密切的关系。我也抱怨过《你有计算过你的通勤成本吗?》,同时,我也有自我鼓励过《再坚持一下就好了》,坚持的内容不算特别成功,但也没有宣告失败。

这个方向关键的地方还是在自己,趁自己还未到中年,尽量多蓄劲,好一举越过中年危机。

总结:

有房有车又如何 还是被生活所追赶 迫不得已的过着 升职了又如何 却是被工作所安排 盲目的适应着 埋怨生活的压力又如何 该做的事情还是得去做 何不开开心心的 抱怨工作的烦恼又如何 该是你的活还是你的活 何不尽快的搞定它 倒是自身的问题不容忽视 学习绝对不能放弃 只有自身不断的提高 才能尽快摆脱生活&工作中的困境

2018年计划:

  • 一次远程旅行,给生活添点乐趣;
  • 一次心里救赎,好好想想自己真正想要的;
  • 一门引以为傲的「手艺」,专注的学点东西;

阅读更多

Access denied for user 'xxx'@'localhost' 报错

Unhandled rejection SequelizeAccessDeniedError: Access denied for user 'lupeng'@'localhost' (using password: YES)

这是Node在使用Sequlize连接Mysql数据时报的错,关键看冒号后面的错误:访问拒绝,关键是访问拒绝的错误,说明数据库连接这里有问题,数据库连接访问拒绝,要么是没有相应的操作权限,要么是账号密码错误。

这样就把问题定位在访问权限以及账号密码错误两点上了,千万不要往其他方面去找问题了,那样只会是浪费时间。

1. 用户权限的问题

权限问题从数据库着手,确认用户授权后,是否刷新的权限列表。也就是在使用Grant命令授权用户后,应该要使用flush privileges命令,这个是很多人会忽略的问题。

如果用户授权没有问题,那么尝试重启mysql服务器。使用命令/etc/init.d/mysql restart重启mysql服务器,不同Linux版本重启命令可能不一样,我这里是Debain系。

如果重启了问题还没有解决,那么可能就不是数据库用户权限的问题了。

2. 账号密码的问题

账号密码错误,这个问题听起来很扯,但是开发过程中,很多人会忽略掉。为什么这么说?我使用的是config-lite模块来配置数据库参数,因为会在多个系统环境中切换开发,使用config-lite模块可以通过简单的环境变量配置,来加载不同的参数文件。具体用法参照:不同环境下配置文件使用 - Node实战 - 技术人生 - SegmentFault

我的问题就出现在这里,打开一个终端运行项目npm run testpackage.json文件里配置着test的运行脚本NODE_ENV=test supervisor --harmony -i views/ ./bin/www。另打开一个终端,运行数据库同步的命令,同步命令是单独写在一个js脚本中,脚本里引用了数据连接方法(通用的),连接方法如下:

var Sequelize = require('sequelize');
// 引入数据库配置文件
var sqlConfig = require('config-lite')(__dirname).mysql;
var sequelize = new Sequelize(sqlConfig.database, sqlConfig.user, sqlConfig.password, {
    host: sqlConfig.host,
    dialect: 'mysql',
    pool: {
        max: 10,
        min: 0,
        idle: 10000
    }
});
module.exports = sequelize;

于是在同步数据库的时候,总是如标题报错,然而觉得没错啊,最后检查才发现问题所在:运行test脚本里的NODE_ENV环境变量只在当前终端下才有效,如果要另开一个终端来同步数据库,那么需要在另开的终端里再设置一下环境变量。不然加载的数据库参数是不一致的,也就是说连接数据库的用户名密码是不对的。

阅读更多

博客时代虽已没落,但内容创作永远不会过时

有人说,别写了,博客时代早就过去了,现在谁还看博客呀,没错,现在确实很少有人再订阅博客来获取资讯了,如今是移动互联网时代,使用电脑订阅资讯的时代一去不复返,但是过时的仅仅只是内容产生的一种方式,更多的方式正在诞生来取代博客。

永远不会过时的是内容创作。

「1」最简单的方式: 直接使用第三方平台

在这个互联网的广阔地域中,我想有一间属于自己的房间,在上面放一些我的「思绪」,「记忆」亦或是「情感」。这类平台有很多,并且基本上涵盖所有的领域。比如博客园 - 开发者的网上家园简书 - 创作你的创作LOFTER(乐乎) - 让兴趣,更有趣SegmentFault,甚至是微博,知乎,豆瓣,汽车之家等等站点基本上都是带有博客属性的。或分享技术,或分享人生经验,或分享书评,影评,车评……

拥有这类博客的方式非常简单,注册对应的账号即可,然后你就可以开始做内容的产出了,坚持下去没准你就成为了某个平台的网红。可是这么多的站点都带有博客属性,我该如何选择呢?其实很简单,平时你在网上搜索文章资讯的时候,你看得比较多的内容产生自哪个平台,那么你就去对应的平台开通博客即可。

这类平台的内容都有很强的用户属性,比如技术人员可能更愿意在CSDN上发表文章,而不会去LOFTER上发表。在功能上都会有各自的一些特点,你可以结合你的需求进行选择,或是拥有多个博客都不是问题,我个人比较喜欢简书上的专题功能,可以创建特定领域的专题,作为版主,你可以收集别人的文章,也可以接受别人的投稿,聚类一些相似主题的文章。

「2」略显极客的方式: 使用Git第三方服务

使用Git服务来搭建一个博客,最开始可能是源于GitHub 上为一些开源项目提供的GitHub Pages服务,它的初衷是为了帮助开发者创建页面来宣传开源项目的。将页面内容push到github的仓库上,就可以通过github提供的域名进行访问了。

官方甚至提供了对Jekyll的支持让你更快捷的搭建页面,什么是Jekyll?Jekyll是一种能够快速将纯文本转化为静态网站和博客的工具,具体的看官方介绍,不多赘述了。Jekyll • 简单的博客、静态网站工具。然而官方提供的这个功能却被大家普遍「滥用」了,大家都用来搭建自己的静态博客网站了。除了Github,还有国内的coding同样也提供这样的服务。

这种使用Git服务的博客方式与上面第三方平台有什么不同呢?为什么称作是略显极客的方式?因为通过它,你完全可以拥有一个完全自由的页面,页面上的所有元素完全由你来定义(需要前端开发技能),还有略显极客的一点就是,你可以通过自己的域名来访问,在这一点上第一种方式可就无法实现了。

这种方式的本质上就是将你创建的静态页面映射出来。利用github和Coding提供的这么一个功能,于是基于Hexo的各式各样的博客站点就诞生了,什么是Hexo呢?Hexo是一个静态页面生成的工具,主要功能就是将Markdown文档转换成静态页面,它不同于Jekyll的最大特色就是博客主题功能的抽象,使用Hexo可以非常方便的制作或是更换博客主题,基于这个特性,你甚至不需要任何的前端开发技能,就可以拥有非常耀眼的博客,并且可以随时切换主题。

于是很多最开始为了博客而使用Hexo的人都去从事页面设计了,我也是其中一个,很长一段时间在做前端页面设计的事情,因为找到一个完全符合自己「品味」的主题没有那么容易,于是修改页面就开始了,随着品味的变化,很不容易设计好的一个页面,没多长时间就看腻了,那么再重来一遍,渐渐都忘了,当初是为了做前端页面设计,还是为了写文章而搭建的博客。

「不要因为走得太远,就忘了当初为什么而出发」,一直很喜欢锤子便签图标上的这句话。

「3」自由极客的方式: 使用自有服务

自由极客通常都喜欢对事物完全的控制,享受一切掌握在自己手中的感觉。就算搭建一个小小的博客也不例外,首先需要一台独立的服务器,拥有对外独立的IP地址,在任何有网络的地方都可以随时访问服务器,做任何不受束缚的更改。

如果把博客当作是一间房间的话,前面所述的第一种方式,利用第三方平台就类似于你租了一间房间,你只有使用权,里面的布局只能按别人给你布置的方式来,有些房东还算开放的话,也许还能让你调调布局啥的,例如博客园等;第二种略显极客的方式就类似于你购买了一套房子,房子里房间的布局你可以随意控制,但是房子的大小是固定的,你无法随心所欲的摆布;而第三种自由极客的方式,就类似于你购置了一块地,你想盖成怎么样的房子,拥有怎样的房间,完全取决于你。你可以盖一栋楼,也可以盖成两栋小的都无所谓,我甚至可以盖其他建筑,例如建个仓库(数据库),建堵墙(代理服务器)用来「翻越长城」。

自由极客的方式的优点就是自由,想要什么网站什么服务都可以实现,更别说区区一个博客了。那么缺点就是你需要有足够的能力,需要时间成本,金钱成本。我相信大部分人购买服务器都不会仅仅为了搭个博客,这有点大材小用了。当然也会有这样的极客存在,可能仅仅只是为了满足完全的控制欲。

自有服务器的开源博客系统,最火的可能就是WordPress了,这也是很多人初学Linux服务器运维的练手项目,想当年自己在虚拟机上为了搭建这么个LMAP环境,对着教程都花了一天的时间,过程中总是会出现各种各样的问题,正所谓「无折腾,不Linux」。

「4」最热门的方式: 微信公众账号

文章最开始的时候就说过,博客时代的没落,并不代表内容产出的没落,写作永远不会过时,即使是人工智能时代的到来,也绝对取代不了人类对于文学、艺术以及思想的创作,因为这些是个性化的,是意识与思想的一种表达,机器是取代不了的。

所以说,过时的只是内容产出的一种方式,在信息时代,最初有社交属性的实现方式应该是论坛,随着内容的细分与聚焦,进而有了个人博客这个载体,再到后来信息爆炸时代,微博取代了博客,直到现在,成为了微信的时代。微信几乎取代了我们社交的方方面面,即时通讯,资讯获取,个性化推荐等等。正是由于微信时代的到来,自媒体这个词才得以膨胀式发展。

只要你想去写,宣泄情感也好,表达观点也罢,那么就去开通微信公众账号吧,没有任何技术门槛,就能拥有当前最热门的「博客」方式,唯一的门槛可能就是你是否有坚持写下去的动力。

「完」

阅读更多