呼叫中心简史

什么是呼叫中心? 呼叫中心又称为客户服务中心。有以下关键词 CTI 通信网络 计算机 企业级 高质量、高效率、全方位、综合信息服务 呼叫中心历史 1956年美国泛美航空公司建成世界第一家呼叫中心。 阶段 行业范围 技术 功能与意义 第一代呼叫中心 民航 PBX、电话排队 主要服务由人工完成 第二代呼叫中心 银行、生活 IVR(交互式语音应答)、DTMF 显著提高工作效率,提供全天候服务 第三代呼叫中心 CTI(电脑计算机集成) 语音数据同步,客户信息存储与查阅,个性化服务,自动化 第四代呼叫中心 接入电子邮件、互联网、手机短信等 多渠道接入、多渠道统一排队 第五代呼叫中心 接入社交网络、社交媒体(微博、微信等) 文本交谈,音频视频沟通 呼叫中心分类 按呼叫方式分类 外呼型呼叫中心(如电话营销) 客服型呼叫中心(如客户服务) 混合型呼叫中心 (如营销和客服) 按技术架构分类 交换机 板卡 软交换(IPCC) 【交换机类型呼叫中心】

2019-01-15 21:04:11 · 1 min · Eddie Wang

时间花在哪里,你就会成为什么样的人

2008-2018 十年,往事如昨 2018年已经是昨天,今天是2019的第一天。 2008年已经是10年前,10年前的傍晚,我走在南京仙林的一个大街上,提着一瓶矿泉水,擦着额头的汗水,仰头看着大屏幕上播放着北京奥运会的开幕式。 10年前的夏天,我带着一步诺基亚手机功能机,独自一人去了南京。 坐过绣球公园的石凳,穿过天妃宫的回廊,吹过阅江楼的凉爽的江风,踏着古老斑驳的城墙,在林荫小路的长椅上,我想着10年后我会在哪里?做着什么事情? 往事如昨,而今将近而立,但是依然觉得自己还是10年的那个独自出去玩的小男孩。 2018 读了10年都没有读完的书,五味杂陈 2018年,在我做手术前,我觉得自己出了工作的时间外,大多数时间都在看书。2018年这一年看的书,要比2008到2018年这十年间的看的书都要多。这都归功于我对每天的看书都有定量的计划,一旦按照这个计划实行几个月,积累的效果还是非常明显的。 2018年,手机几乎成为人的四肢之外的第五肢。对大多人来说,上厕所可以不带纸,但是不能不带手机。 各种APP, 都在极力的吸引用户多花点时间在自己身上 信息流充斥着各种毫无营养,专门吸人眼球的垃圾新闻,但是这种新闻的阅读量还是蛮大的 各种借钱,信用卡,花呗等都像青楼的小姐,妩媚的笑容,说道:官人,进来做一做 共享单车,在今年退潮之后,才发现自己都在裸泳 比特币,挖矿机。不知道谁割了谁的韭菜,总希望有下一个傻子来接盘,最后发现自己可能就是最后一个傻子 AI,人工智能很火,放佛就快要进入终结者那样的世界 锤子垮了,曾经吹过的牛逼,曾经理想主义终于脱去那又黑又亮的面具 图灵测试(The Turing test)由艾伦·麦席森·图灵发明,指测试者与被测试者(一个人和一台机器)隔开的情况下,通过一些装置(如键盘)向被测试者随意提问。 进行多次测试后,如果有超过30%的测试者不能确定出被测试者是人还是机器,那么这台机器就通过了测试,并被认为具有人类智能。图灵测试一词来源于计算机科学和密码学的先驱阿兰·麦席森·图灵写于1950年的一篇论文《计算机器与智能》,其中30%是图灵对2000年时的机器思考能力的一个预测,目前我们已远远落后于这个预测。 最后说一下图灵测试,在AI方面,这个测试无人不知。一个机器如果通过了图灵测试,则说明该机器具有了只能。但是三体的作者大刘曾经说过一句话,给我一种醍醐灌顶的感觉,假如一个机器人有能力通过图灵测试,却假装无法通过,你说这个机器是否具有人工智能。所以大刘的这种说法才更加让人恐惧。机器人能通过图灵测试,只说明这个机器人具有了智能。但是现阶段的智能只不过是条件反射,或者是基于概率计算的结果。后者这种能通话测试,却假装无法通过的智能。这不仅仅是智能,而是机器的城府。 有智能的机器并不可怕,有城府的机器人才是真正的可怕。 如果梦中更加幸福快乐,为什么要回到现实 火影的最后,大筒木辉夜使用无限月读将世界上的所有人都带入梦境,每个人的查克拉都被吸取,并作为神树的养料。 如果真的存在大筒木这样的上帝,那么时间就是查克拉。人类唯一真正拥有过的东西,时间,将作为神树的养料,从每个人身上提取。 各种具有吸引力的术,其实可以理解为无限月读,让人沉醉于梦幻中。 如果梦中更加幸福快乐,为什么要回到现实中承受压力与悲哀呢? 目前我无法回复自己的这个问题,期待2019年我可以得到这个答案。 工作方面 2019年,我会在做一些后端方面的工作,努力加油吧。

2019-01-01 21:02:08 · 1 min · Eddie Wang

深入理解 JavaScript中的变量、值、函数传参

1. demo 如果你对下面的代码没有任何疑问就能自信的回答出输出的内容,那么本篇文章就不值得你浪费时间了。 var var1 = 1 var var2 = true var var3 = [1,2,3] var var4 = var3 function test (var1, var3) { var1 = 'changed' var3[0] = 'changed' var3 = 'changed' } test(var1, var3) console.log(var1, var2, var3, var4) 2. 深入理解原始类型 原始类型有5个 Undefinded, Null, Boolean, Number, String 2.1. 原始类型变量没有属性和方法 // 抬杠, 下面的length属性,toString方法怎么有属性和方法呢? var a = 'oooo' a.length a.toString 原始类型中,有三个特殊的引用类型Boolean, Number, String,在操作原始类型时,原始类型变量会转换成对应的基本包装类型变量去操作。参考JavaScript高级程序设计 5.6 基本包装类型。 2.2. 原始类型值不可变 原始类型的变量的值是不可变的,只能给变量赋予新的值。 下面给出例子 // str1 开始的值是aaa var str1 = 'aaa' // 首先创建一个能容纳6个字符串的新字符串 // 然后再这个字符串中填充 aaa和bbb // 最后销毁字符串 aaa和bbb // 而不能理解成在str1的值aaa后追加bbb str1 = str1 + 'bbb' 其他原始类型的值也是不可变的, 例如数值类型的。 2.3. 原始类型值是字面量 3. 变量和值有什么区别? 不是每一个值都有地址,但每一个变量有。《Go程序设计语言》 变量没有类型,值有。变量可以用来保存任何类型的值。《You-Dont-Know-JS》 变量都是有内存地址的,变量有用来保存各种类型的值;不同类型的值,占用的空间不同。 var a = 1 typeof a // 检测的不是变量a的类型,而是a的值1的类型 4. 变量访问有哪些方式? 变量访问的方式有两种: ...

2018-12-17 15:24:15 · 2 min · Eddie Wang

WTF!! Vue数组splice方法无法正常工作

当函数执行到this.agents.splice()时,我设置了断点。发现传参index是0,但是页面上的列表项对应的第一行数据没有被删除, WTF!!! 这是什么鬼!然后我打开Vue Devtools, 然后刷新了一下,发现那个数组的第一项还是存在的。什么鬼?? removeOneAgentByIndex: function (index) { this.agents.splice(index, 1) } 然后我就谷歌了一下,发现这个splice not working properly my object list VueJs, 大概意思是v-for的时候最好给列表项绑定:key=。然后我是试了这个方法,发现没啥作用。 最终我决定,单步调试,如果我发现该问题出在Vue自身,那我就该抛弃Vue, 学习React了 单步调试中出现一个异常的情况,removeOneAgentByIndex是被A函数调用的,A函数由websocket事件驱动。正常情况下应该触发一次的事件,服务端却发送了两次到客户端。由于事件重复,第一次执行A删除时,实际上removeOneAgentByIndex是执行成功了,但是重复的第二个事件到来时,A函数又往agents数组中添加了一项。导致看起来,removeOneAgentByIndex函数执行起来似乎没有设么作用。而且这两个重复的事件是在几乎是在同一时间发送到客户端,所以我几乎花了将近一个小时去解决这个bug。引起这个bug的原因是事件重复,所以我在前端代码中加入事件去重功能,最终解决这个问题。 我记得之前看过一篇文章,一个开发者调通过回调函数计费,回调函数是由事件触发,但是没想到有时候事件会重发,导致重复计费。后来这名开发者在自己的代码中加入事件去重的功能,最终解决了这个问题。 事后总结:我觉得我不该怀疑Vue这种库出现了问题,但是我又不禁去怀疑。 通过这个bug, 我也学到了第二方法,可以删除Vue数组中的某一项,参考下面代码。 // Only in 2.2.0+: Also works with Array + index. removeOneAgentByIndex: function (index) { this.$delete(this.agents, index) } 另外Vue devtools有时候并不会实时的观测到组件属性的变化,即使点了Refresh按钮。如果点了Refresh按钮还不行,那建议你重新打开谷歌浏览器的devtools面板。

2018-12-12 20:29:16 · 1 min · Eddie Wang

Node.js 如何找出循环依赖的文件?如何解决循环依赖问题?

本文重点是讲解如何解决循环依赖这个问题。关心这个问题是如何产生的,可以自行谷歌。 如何重现这个问题 // a.js const {sayB} = require('./b.js') sayB() function sayA () { console.log('say A') } module.exports = { sayA } // b.js const {sayA} = require('./a.js') sayA() function sayB () { console.log('say B') } module.exports = { sayB } 执行下面的代码 ➜ test git:(master) ✗ node a.js /Users/dd/wj-gitlab/tools/test/b.js:3 sayA() ^ TypeError: sayA is not a function at Object.<anonymous> (/Users/dd/wj-gitlab/tools/test/b.js:3:1) at Module._compile (module.js:635:30) at Object.Module._extensions..js (module.js:646:10) at Module.load (module.js:554:32) at tryModuleLoad (module.js:497:12) at Function.Module._load (module.js:489:3) at Module.require (module.js:579:17) at require (internal/module.js:11:18) at Object.<anonymous> (/Users/dd/wj-gitlab/tools/test/a.js:1:78) at Module._compile (module.js:635:30) sayA is not a function那么sayA是个什么呢,实际上它是 undefined ...

2018-10-29 09:21:03 · 2 min · Eddie Wang

shields小徽章是如何生成的?以及搭建自己的shield服务器

shields小徽章介绍 一般开源项目都会有一些小徽章来标识项目的状态信息,并且这些信息是会自动更新的。在shields的官网https://shields.io/#/, 上面有各种各样的小图标,并且有很多自定义的方案。 起因:如何给私有部署的jenkins制作shields服务? 私有部署的jenkins是用来打包docker镜像的,而我想获取最新的项目打包的jenkins镜像信息。但是私有的jenkins项目信息,公网的shields服务是无法获取其信息的。那么如果搭建一个私有的shields服务呢? 第一步:如何根据一些信息,制作svg图标 查看shields图标的源码,可以看到这些图标都是svg格式的图标。然后的思路就是,将文字信息转成svg图标。最后我发现这个思路是个死胡同, 有个npm包叫做,text-to-svg, 似乎可以将文本转成svg, 但是看了文本转svg的效果,果断就放弃了。 最后回到起点,看了shields官方仓库,发现一个templates目录,豁然开朗。原来svg图标是由svg的模板生成的,每次生成图标只需要将信息添加到模板中,然后就可以渲染出svg字符串了。 顺着这个思路,发现一个包shields-lightweight var shields = require('shields-lightweight'); var svgBadge = shields.svg('subject', 'status', 'red', 'flat'); 这个包的确可以生成和shields一样的小徽章,但是如果徽章中有中文,那么中文就会溢出。因为一个中文字符的宽度要比一个英文字符宽很多。 所以我就fork了这个项目,重写了图标宽度计算的方式。shields-less npm install shields-less var shieldsLess = require('shields-less') var svgBadge = shieldsLess.svg({ leftText: 'npm 黄河远上白云间', rightText: 'hello 世界' }) var svgBadge2 = shieldsLess.svg({ leftText: 'npm 黄河远上白云间', rightText: 'hello 世界', style: 'square' }) var svgBadge2 = shieldsLess.svg({ leftText: 'npm 黄河远上白云间', rightText: 'hello 世界', leftColor: '#e64a19', rightColor: '#448aff', style: 'square' // just two style: square and plat(default) }) 渲染后的效果,查看在线demo: https://wdd.js.org/shields-less/example/ ...

2018-10-29 09:14:43 · 1 min · Eddie Wang

Express代理中间件问题与解决方案

前后端分离应用的架构 在前后端分离架构中,为了避免跨域以及暴露内部服务地址。一般来说,我会在Express这层中加入一个反向代理。 所有向后端服务访问的请求,都通过代理转发到内部的各个服务。 这个反向代理服务器,做起来很简单。用http-proxy-middleware这个模块,几行代码就可以搞定。 // app.js Object.keys(proxyTable).forEach(function (context) { app.use(proxyMiddleware(context, proxyTable[context])) }) http-proxy-middleware实际上是对于node-http-proxy的更加简便的封装。node-http-proxy是http-proxy-middleware的底层包,如果node-http-proxy有问题,那么这个问题就会影响到http-proxy-middleware这个包。 最近的bug http-proxy-middleware最近有个问题,请求体在被代理转发前,如果请求体被解析了。那么后端服务将会收不到请求结束的消息,从浏览器的网络面板可以看出,一个请求一直在pending状态。 Cannot proxy after parsing body #299, 实际上这个问题在node-http-proxy也被提出过,而且处于open状态。POST fails/hangs examples to restream also not working #1279 目前这个bug还是处于open状态,但是还是有解决方案的。就是将请求体解析的中间件挂载在代理之后。 下面的代码,express.json()会对json格式的请求体进行解析。方案1在代理前就进行body解析,所有格式是json的请求体都会被解析。 但是有些走代理的请求,如果我们并不关心请求体的内容是什么,实际上我们可以不解析那些走代理的请求。所以,可以先挂载代理中间件,然后挂载请求体解析中间件,最后挂载内部的一些接口服务。 // 方案1 bad app.use(express.json()) Object.keys(proxyTable).forEach(function (context) { app.use(proxyMiddleware(context, proxyTable[context])) }) app.use('/api', (req, res, next)=> { }) // 方案2 good Object.keys(proxyTable).forEach(function (context) { app.use(proxyMiddleware(context, proxyTable[context])) }) app.use(express.json()) app.use('/api', (req, res, next)=> { }) 总结 经过这个问题,我对Express中间件的挂载顺序有了更加深刻的认识。 同时,在使用第三方包的过程中,如果该包bug,那么也需要自行找出合适的解决方案。而这个能力,往往就是高手与新手的区别。

2018-09-30 09:41:44 · 1 min · Eddie Wang

IE11跨域检查跨域设置

IE11有安全设置中有两个选项, 跨域浏览窗口和框架 通过域访问数据源 如果上面两个选项被禁用,那么IE11会拒绝跨域请求。如果想要跨域成功,必须将上面两个选项设置为启用。 第一步 打开IE11 点击浏览器右上角的齿轮图标 点击弹框上的 Internet选项 第二步 点击安全 点击Internet 点击自定义级别 第三步 找到跨域浏览窗口和框架 如果这项是禁用的,那么要勾选启用。 找到通过域访问数据源 如果这项是禁用的,那么要勾选启用。 最后在点击确定。 最后,如果跨域浏览窗口和框架,通过域访问数据源都启用了,还是无法跨域。那么最好重启一下电脑。有些设置可能在重启后才会生效。

2018-08-23 10:20:10 · 1 min · Eddie Wang

毕业后,青春像一艘船,沉入海底

大三那年的暑假 大三那年暑假,很多同学都回去了,寝室大楼空空如也。 留在上海的同学都在各自找着兼职的工作,为了不显得无聊,我也在网上随便发了一些简历,试试看运气。 写简历最难写的部分就是写你自己的长处是什么?搜索枯肠,觉得自己似乎也没什特长。感觉大学三年学到一些东西,又感觉什么都没学到。 如果没有特长,总该也有点理想吧,比如想干点什么? 似乎我也没什么想做的事情。 小时候我们都有理想,慢慢长大后,理想越来越模糊,变得越来越迷茫。 大学里,大部分的人都是在打游戏。我也曾迷恋过打游戏,但是因为自己比较菜,总是被虐,所以放弃了。 但是我也不是那种天天对着笔记本看电视剧的人。 回忆初三那年的暑假 记得,初三的暑假,我参加了一个学校看展的一个免费的计算机培训班。因为培训的老师说,培训结束前会有一个测试,成绩最好的会有几百块的奖励。 为了几百块的奖励,我第一个背诵完五笔拆字法。随后老师教了我们PS, 就是photoshop。当时我的理解就是,ps可以做出很多搞笑的图片。 为了成为一个有能力做出搞笑图片的人。我在高中和大学期间,断断续续的系统的自学了PS。 下面给展示几张我的PS照片 【毕业照】 【帮别人做的艺术照】 【刺客信条 换脸 我自己】 【旅游照 换脸 我自己】 【宿舍楼 上面ps了一条狼】 古玩艺术电商中的店小二 基本上,我的PS技术还是能够找点兼职做的。没过多久,我收到了面试邀请,面试的公司位于一个古玩收藏品市场中。 当然我面试成功了,开出的日薪也是非常诱人,每天35元。 在上海,35元一天的工资,除去来回上下班做地铁和公交,还有中午饭的费用外,基本上不会剩下什么,有时候稍微午饭丰盛点,自己就要倒贴。但是这也是一次不错的尝试,至少有史以来,除去父母以外,我用能力问别人要钱了。 35元的日薪持续很短一段时间,然后我就涨薪了,到达每天100元。在这个做兼职的地方,我最高拿到的日薪是200元。 兼职期间我做了各式各样的工作: 古玩艺术品摄影 海报制作 拍卖图册制作 linux运维 APP UI 设计 网页设计 python爬虫 兼职的日志过得很苦,单是还算充实。虽然工资不高,但是因为还没毕业,也没有奢望过高的工资。 【上图 我在一个古玩店的拍摄玉器的时候,有个小女孩过来找我玩,我随手拍的】 【上图 是在1号线 莲花路地铁站 因为错过了地铁拍的】 【上图 是从1号线 莲花地铁站 转公交拍的】 【每天早上起的很早,能够看到军训的学生在操场上奔跑】 【在古玩店一般都要拍到很晚,因为是按张数算拍照工资,拍的越多,工资越高。还好晚上回公司 打车费用是可以报销的】 ...

2018-08-14 18:36:40 · 1 min · Eddie Wang

NodeJS Events 模块笔记

1. 环境 node 8.11.3 2. 基本使用 // 01.js const EventEmitter = require('events'); class MyEmitter extends EventEmitter {} const myEmitter = new MyEmitter(); myEmitter.on('event', () => { console.log('an event occurred!'); }); myEmitter.emit('event'); 输出: an event occurred! 3. 传参与this指向 emit()方法可以传不限制数量的参数。 除了箭头函数外,在回调函数内部,this会被绑定到EventEmitter类的实例上 // 02.js const EventEmitter = require('events') class MyEmitter extends EventEmitter {} const myEmitter = new MyEmitter() myEmitter.on('event', function (a, b){ console.log(a, b, this, this === myEmitter) }) myEmitter.on('event', (a, b) => { console.log(a, b, this, this === myEmitter) }) myEmitter.emit('event', 'a', {name:'wdd'}) 输出: ...

2018-08-10 10:18:57 · 2 min · Eddie Wang