2016年12月21日 星期三

今天是冬至

纪念一下6年前的这天,那时的我应该在流泪,从来没有的失落和痛心。一切就像我那时劝告自己的说的,时间可以解决一切。

2016年12月20日 星期二

前端,是一种GUI软件

喂喂喂,那个切图的,把页面写好就发给研发工程师套模板吧。

你好,切图仔。

不知道你的团队如何定义前端开发,据我所知,时至今日仍然有很多团队会把前端开发归类为产品或者设计岗位,虽然身份之争多少有些无谓,但我对这种偏见还是心存芥蒂,酝酿了许久,决定写一个系列的文章,试着从工程的角度系统的介绍一下我对前端,尤其是Web前端的理解。

只要我们还把自己的工作看作为一项软件开发活动,那么我相信读过下面的内容你也一定会有所共鸣。

前端,是一种GUI软件

现如今前端可谓包罗万象,产品形态五花八门,涉猎极广,什么高大上的基础库/框架,拽炫酷的宣传页面,还有屌炸天的小游戏……不过这些一两个文件的小项目并非是前端技术的主要应用场景,更具商业价值的则是复杂的Web应用,它们功能完善,界面繁多,为用户提供了完整的产品体验,可能是新闻聚合网站,可能是在线购物平台,可能是社交网络,可能是金融信贷应用,可能是音乐互动社区,也可能是视频上传与分享平台……

从本质上讲,所有Web应用都是一种运行在网页浏览器中的软件,这些软件的图形用户界面(Graphical User Interface,简称GUI)即为前端。

如此复杂的Web应用,动辄几十上百人共同开发维护,其前端界面通常也颇具规模,工程量不亚于一般的传统GUI软件:

尽管Web应用的复杂程度与日俱增,用户对其前端界面也提出了更高的要求,但时至今日仍然没有多少前端开发者会从软件工程的角度去思考前端开发,来助力团队的开发效率,更有甚者还对前端保留着”如玩具般简单“的刻板印象,日复一日,刀耕火种。

历史悠久的前端开发,始终像是放养的野孩子,原始如斯,不免让人慨叹!

2016年12月19日 星期一

导出带图片的Excel

导出二维数据excel,其实很简单,使用cvs就可以了。但是如果导出格式复杂还带样式还带图片的怎么办?客户有时就是这部变态。呵呵。如果是用.net,微软提供的有库,使用php也提供的有库。大致了解一下,都可以实现带图片。可惜我现在使用的golang没有那么库支持。只能裸搞了。


excel应该分两种,一种是office 2007以前的和office 2007以后的,office 2007 以后的版本和现在wps都支持Open XML 了。2007年到现在都7年了,所以这次我们就使用Open XML 技术解决我们的问题。

通过对Open XML 文档学习,大致实现步骤可以分三步:
1、使用office 2010制作一个我们想要样式的excel。

2、解压后使用占位符,修改里面相应的XML文件,然后压缩,这个压缩文件称为模板.

3、程序解压这个模板,使用查询的数据替换里面的占位符,最后再压缩,这个压缩文件就是我们最终的结果。
func (c Order) Excel(pageIndex int, pageSize int, sortField string, sortOrder string, customId int64, state string, orderTime string) revel.Result {
	sql := "select a.name A,b.name B,e.name C,d.name D,c.name E,a.order_time F,a.money G,a.state H,a.image I,a.width J,a.height K,a.area L,a.unit M,a.amount N,a.price O,f.alias P,a.remarks Q from ad_order a,ad_custom b,ad_product c,ad_stuff d,ad_stuff_cat e,ad_user f where a.product_id=c.id and c.stuff_id=d.id and d.cat_id=e.id and a.custom_id=b.id and a.user_id=f.id and a.del_state='未删' %s %s %s order by a.id desc"
	sql = fmt.Sprintf(sql, fmt.Sprintf("and a.custom_id=%d", customId), "%s", "%s")
	if state != "" {
		sql = fmt.Sprintf(sql, fmt.Sprintf("and a.state='%s'", state), "%s")
	} else {
		sql = fmt.Sprintf(sql, "", "%s")
	}
	if orderTime != "" {
		sql = fmt.Sprintf(sql, fmt.Sprintf("and a.order_time='%s'", orderTime))
	} else {
		sql = fmt.Sprintf(sql, "")
	}
	orders, err := Orm.Query(sql)
	if err != nil {
		return c.RenderJson(models.Message{State: "failure", Msg: err.Error()})
	}
	rows := make([]Rows, 0)
	col := 17
	for i := 1; i <= len(orders); i++ {
		row := Rows{}
		row.RowId = i + 1
		for k := 0; k < col; k++ {
			row.Columns = append(row.Columns, Columns{R: fmt.Sprintf("%s%d", string(ABC[k]), i+1), V: i*col + k})
		}
		rows = append(rows, row)
	}
	vmlDrawings := make([]VmlDrawing, 0)
	sharedStrings := make([]string, 0)
	sharedStrings = append(sharedStrings, "订单名称")
	sharedStrings = append(sharedStrings, "客户名称")
	sharedStrings = append(sharedStrings, "产品目录")
	sharedStrings = append(sharedStrings, "产品材料")
	sharedStrings = append(sharedStrings, "产品名称")
	sharedStrings = append(sharedStrings, "订单日期")
	sharedStrings = append(sharedStrings, "金额")
	sharedStrings = append(sharedStrings, "收费状态")
	sharedStrings = append(sharedStrings, "产品图片")
	sharedStrings = append(sharedStrings, "宽度(米)")
	sharedStrings = append(sharedStrings, "高度(米)")
	sharedStrings = append(sharedStrings, "面积")
	sharedStrings = append(sharedStrings, "单位")
	sharedStrings = append(sharedStrings, "数量")
	sharedStrings = append(sharedStrings, "单价")
	sharedStrings = append(sharedStrings, "经手人")
	sharedStrings = append(sharedStrings, "备注")
	for i, row := range orders {
		if string(row["I"]) != "" {
			img := string(row["I"])
			vmlDrawing := VmlDrawing{}
			vmlDrawing.Index = i
			vmlDrawing.Id = img[:strings.Index(img, ".")]
			vmlDrawing.Name = fmt.Sprintf("S%s", img)
			vmlDrawing.RowBegin = i + 1
			vmlDrawing.RowEnd = i + 2
			vmlDrawings = append(vmlDrawings, vmlDrawing)
		}
		sharedStrings = append(sharedStrings, string(row["A"])) //订单名称
		sharedStrings = append(sharedStrings, string(row["B"])) //客户名称
		sharedStrings = append(sharedStrings, string(row["C"])) //产品目录
		sharedStrings = append(sharedStrings, string(row["D"])) //产品材料
		sharedStrings = append(sharedStrings, string(row["E"])) //产品名称
		sharedStrings = append(sharedStrings, string(row["F"])) //订单日期
		f1, _ := strconv.ParseFloat(string(row["G"]), 32)
		sharedStrings = append(sharedStrings, fmt.Sprintf("%.2f", f1)) //金额
		sharedStrings = append(sharedStrings, string(row["H"]))        //收费状态
		sharedStrings = append(sharedStrings, "")                      //产品图片
		f2, _ := strconv.ParseFloat(string(row["J"]), 32)
		sharedStrings = append(sharedStrings, fmt.Sprintf("%.2f", f2)) //宽度(米)
		f3, _ := strconv.ParseFloat(string(row["K"]), 32)
		sharedStrings = append(sharedStrings, fmt.Sprintf("%.2f", f3)) //高度(米)
		f4, _ := strconv.ParseFloat(string(row["L"]), 32)
		sharedStrings = append(sharedStrings, fmt.Sprintf("%.4f", f4)) //面积
		sharedStrings = append(sharedStrings, string(row["M"]))        //单位
		sharedStrings = append(sharedStrings, string(row["N"]))        //数量
		f5, _ := strconv.ParseFloat(string(row["O"]), 32)
		sharedStrings = append(sharedStrings, fmt.Sprintf("%.2f", f5)) //单价
		sharedStrings = append(sharedStrings, string(row["P"]))        //经手人
		sharedStrings = append(sharedStrings, string(row["Q"]))        //备注
	}
	basePath := revel.BasePath
	basePathPrefix := fpath.Join(basePath, fpath.FromSlash("app/templates"))
	file, _ := os.Create(fpath.Join(basePathPrefix, fpath.FromSlash(fmt.Sprintf("%s.xlsx", "orders"))))
	w := zip.NewWriter(file)
	defer w.Close()
	r, _ := zip.OpenReader(fpath.Join(basePathPrefix, fpath.FromSlash(fmt.Sprintf("%s.xlsx", "order"))))
	defer r.Close()
	for _, f := range r.File {
		switch f.Name {
		case "xl/worksheets/sheet1.xml":
			buf := new(bytes.Buffer)
			rc, _ := f.Open()
			data, _ := ioutil.ReadAll(rc)
			rc.Close()
			tmpl, _ := template.New("sheet").Parse(string(data))
			tmpl.Execute(buf, rows)
			ff, _ := w.Create(f.Name)
			ff.Write(buf.Bytes())
			break
		case "xl/sharedStrings.xml":
			buf := new(bytes.Buffer)
			rc, _ := f.Open()
			data, _ := ioutil.ReadAll(rc)
			rc.Close()
			tmpl, _ := template.New("sharedStrings").Parse(string(data))
			tmpl.Execute(buf, sharedStrings)
			ff, _ := w.Create(f.Name)
			ff.Write(buf.Bytes())
			break
		case "xl/drawings/_rels/vmlDrawing1.vml.rels":
			buf := new(bytes.Buffer)
			rc, _ := f.Open()
			data, _ := ioutil.ReadAll(rc)
			rc.Close()
			tmpl, _ := template.New("vmlDrawing1.vml").Parse(string(data))
			tmpl.Execute(buf, vmlDrawings)
			ff, _ := w.Create(f.Name)
			ff.Write(buf.Bytes())
			break
		case "xl/drawings/vmlDrawing1.vml":
			buf := new(bytes.Buffer)
			rc, _ := f.Open()
			data, _ := ioutil.ReadAll(rc)
			rc.Close()
			tmpl, _ := template.New("vmlDrawing1").Parse(string(data))
			tmpl.Execute(buf, vmlDrawings)
			ff, _ := w.Create(f.Name)
			ff.Write(buf.Bytes())
			basePath := revel.BasePath
			basePathPrefix := fpath.Join(basePath, fpath.FromSlash("public/upload"))
			for _, v := range vmlDrawings {
				fsmall := fpath.Join(basePathPrefix, fpath.FromSlash(v.Name))
				file, _ := os.Open(fsmall)
				data, _ := ioutil.ReadAll(file)
				ff, _ := w.Create(fmt.Sprintf("xl/media/%s", v.Name))
				ff.Write(data)
			}
			break
		default:
			ff, _ := w.Create(f.Name)
			rc, _ := f.Open()
			data, _ := ioutil.ReadAll(rc)
			ff.Write(data)
			rc.Close()
		}
	}
	return c.RenderFile(file, revel.Attachment)
}

2016年12月19日 星期一

路由器作为交换机

1.把DHCP关闭
2.把lan的IP改为三层网段
3.把上层网段,插入lan口

2016年12月19日 星期一

Git for windows 中文乱码解决方案

Git 是在linux下开发的,而 Linux 的编码方式是基于 UTF-8 的,所以移植到 Windows 之后难免会存在编码冲突,导致乱码。Git 在 Windows 下有多种乱码情况,请按具体情况操作~
假设 Git 安装目录为 C:\Git

1.使用 git add 命令添加文件名含中文字符的文件时

1.1 乱码类似:
    \316\304\261\276\316\304\265\265.txt
1.2 解决方案:

编辑 C:\Git\etc\inputrc 文件中对应的行,查找以下2行,并修改其值,
原先:

setoutput-meta off
    setconvert-meta on

改为:

setoutput-meta onsetconvert-meta off

2.使用git log查看含有中文的log信息时

2.1 乱码类似:
<E4><BF><AE><E6><94><B9><E6><96><87><E6><9C><AC><E6><96><87><E6><A1><A3>
2.2 解决方案:

在Bash提示符下输入:

    git config --global i18n.commitencoding utf-8
    git config --global i18n.logoutputencoding gbk

注:设置 commit 提交时使用 utf-8 编码,可避免 Linux 服务器上乱码;同时设置在执行 git log 时将 utf-8 编码转换成 gbk 编码,以解决乱码问题。
编辑 C:\Git\etc\profile 文件,添加如下一行:

export LESSCHARSET=utf-8

注:以使git log可以正常显示中文(需要配合:i18n.logoutputencoding gbk

3.使用ls命令查看含有中文的文件名乱码时

3.1 乱码类似:
    ????.txt
    ???????.md
3.2 解决方案:

使用 ls --show-control-chars 命令来强制使用控制台字符编码显示文件名,即可查看中文文件名。
为了方便使用,可以编辑 C:\Git\etc\git-completion.bash 文件,添加如下一行:

alias ls="ls --show-control-chars"

4.在Git Gui中查看UTF-8编码的文本文件时

4.1 乱码类似:
    锘夸腑鏂囨枃妗£
4.2 解决方案:

在Bash提示符下输入:

    git config --global gui.encoding utf-8

注:通过上述设置,UTF-8 编码的文本文件可以正常查看,但是 GBK 编码的文件将会乱码,所以还是没有从根本上解决问题。

可行的方法之一为:将所有文本文件的编码统一为 UTF-8 或 GBK,然后设置相应的gui.encoding 参数为 utf-8 gbk


2016年12月19日 星期一

ubuntu server 开启 root 用户,并设置允许 ssh

1.启动root帐号
sudo passwd root
根据提示输入root密码
2.允许root 使用ssh
因为新版shs在sshd_config里面有了限制
#vim /etc/ssh/sshd_config
# Authentication:

LoginGraceTime 120

#PermitRootLogin without-password    #找到这里,把它注释

PermitRootLogin yes                  #改为yes  然后重启ssh
StrictModes yes
#service ssh restart


#Tips:这里注意/etc/init.d/ssh restart 用这个方式重启是不成功的。

2016年12月19日 星期一

ionic 常用命令

即使是比较优秀的开源项目,文档还是不能把所有问题描述清楚,所以最直接的方式是,直接看源码。在使用ionic过程中,最关心的几个命令文档中没有描述,比如,更新平台代码,而不是每次都要重新add。

下面就把常用的几个命令,列出来,以便以后不用再看源码了。

1、添加平台,这个文档有
    ionic platform add andriod
2、更新平台,这个文档没有,也是我比较关心的一个,比如我更新了html一段代码,或修改了图标,或修改了插件,AS (andriod studio),打开项目这么慢,我可能不想删除重新add。
    ionci platform update andriod
3、检查某个平台项目,比如资源缺失,命名不正确等,比如:cp: no such file or directory: E:\Workspaces\Android\emobile\resources\android\icon\drawable-ldpi-icon.png
 ionic platform check andriod
4、 移除某个平台,这个不太重要,因为我们可以直接删除文件夹,不过最好是使用命令删除好了
ionic paltform remove andriod 或 ionic platform rm andriod

2016年12月19日 星期一

MX5 ADB 链接error: device not found

这个问题郁闷了好久,因为事情比较忙也没时间解决。每次是开启360 一键 root 勉强调试。今天狠下心把它解决了。解决办法有以下几个步骤:

1、连接方式改成 “内置光盘”,这样手机第一次连接会安装驱动。
2、完成1步骤,如果还有adb interface 驱动没有安装,你需要到网上找这个驱动安装。
3、在自己电脑C:\Users\Administrator\.android 目录防止一个adb_usb.ini文件,里面写上设备ID(0x2A45)。设备ID查看方法是在设备管理,点击adb interface 驱动详情里面有。如下图
4、完成后,重新链接插上手机即可。

2016年12月19日 星期一

编译webrtc 下的 apk

sudo apt-get install git
sudo apt-get install openjdk-8-jdk
export PATH=$PATH:$HOME/depot_tools
export GYP_DEFINES="OS=android"
source .profile
fetch --nohooks webrtc_android
gclient sync

再次设置环境变量
export GYP_DEFINES="OS=android $GYP_DEFINES"
export GYP_GENERATOR_FLAGS="$GYP_GENERATOR_FLAGS output_dir=out_android"

source .profile

2016年12月18日 星期天

海狮表演

小时候没有看的,都陪儿子看几遍