Tag Archives: 产品设计

Hello World 业界杂谈

微信二维码登录功能的实现

微信的二维码登录是个很酷的功能:客户端登录后,通过扫描web端的二维码,实现统一用在web端的登录

下面要讲的就是如何这一个功能:

实现思路:
web:访问web页面时,如果未登陆,会根据随机字符串生成二维码,显示到页面上,同时将该字符串保存起来,然后页面会通过ajax轮询方式访问web端,查看这个二维码是否可以登录,如果可以登录,则将用户名/id写入session,然后将页面跳转到登录状态
客户端:扫描页面的二维码后,通过http方式访问web端,将二维码源字符串,以及客户端登录用户的用户名/id发送过去,告诉web端这个用户可以登录

思路很简单,实现起来也不麻烦,下面会列一些核心代码,详细的,请看这个demo,代码可以到这里下载

web端:
二维码生成,使用qrcode库:

/*
 * $source  二维码源字符串
 * $temp  图片缓存目录
 * $errorCorrectionLevel, $matrixPointSize 错误等级、图片大小
 */
function getQRCodeImg($source, $temp, $errorCorrectionLevel, $matrixPointSize){
	$date = date('Ymd');
	$PNG_WEB_DIR = DIRECTORY_SEPARATOR.$temp.DIRECTORY_SEPARATOR.$date.DIRECTORY_SEPARATOR;
	$PNG_TEMP_DIR = dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'webroot'.DIRECTORY_SEPARATOR.$temp.DIRECTORY_SEPARATOR.$date.DIRECTORY_SEPARATOR;
	include_once '../lib/qrcode/qrlib.php';
	if (!file_exists($PNG_TEMP_DIR))
		mkdir($PNG_TEMP_DIR);
 
	if (!in_array($errorCorrectionLevel, array('L','M','Q','H')))
		$errorCorrectionLevel = 'M';    
 
	$matrixPointSize = min(max((int)$matrixPointSize, 1), 10);
 
	$filename = md5($source.'|'.$errorCorrectionLevel.'|'.$matrixPointSize).'.png';
 
	QRcode::png($source, $PNG_TEMP_DIR.$filename, $errorCorrectionLevel, $matrixPointSize, 2); 
 
	return $PNG_WEB_DIR.$filename;
}

页面的ajax相当简单:

//ajax轮询时间间隔,通过服务器配置得到
var ASK_TIME = <?php echo conf('ajax.time');?>;
var i = 0;
$(function(){
	setInterval(function(){
		$.get('page_ask.php?source=<?php echo $source;?>', function(d){
			//登录成功,跳转页面
			if(d && d.login){
				window.location = '';
			}
			//测试信息的显示
			$('div.test').html(i++ + '---' + JSON.stringify(d));
		}, 'json');
	}, ASK_TIME * 1000);
});

page_ask.php的核心代码,服务端存储使用mongodb

//ajax轮询检查是否登录		登录成功返回user,否则为false 
function checkSource($source){
	$collection = getDBCollection(conf('mongo.collection'));
	$sou = $collection->findone(array('_id' => $source));
	if($sou && $sou['login'] === 1){
		return $sou['user'];
	}
	return false;
}

客户端通过访问“/client_login.php?source=xxx&user=张三”实现登录,当然,实际的系统应该是传userId

//取记录  返回  1 登录成功  10 source有误  11 此source已使用过  21 无此user(暂无此项)
function checkSource4Login($source, $user){
	$collection = getDBCollection(conf('mongo.collection'));
	$sou = $collection->findone(array('_id' => $source));
	$r = 10;
	if($sou && isset($sou['login'])){
		if($sou['login'] === 0){
			$r = 1;//校验正确
		}else{
			$r = 11;
		}
	}
	//保存登录状态
	if($r == 1){
		//保存登录状态
		$collection->update(
			array('_id' => $source), 
			array('$set' => array('login' => 1, 'user' => $user)), 
			array('safe'=>true)
		);
	}
	return $r;
}

下面是客户端的几个片段,这里使用的是ios
二维码扫描使用的库是ZBar,注意,需要添加一坨frameworks

-(IBAction)startScan:(id)sender
{
    ZBarReaderViewController *reader = [ZBarReaderViewController new];
    reader.readerDelegate = self;
    ZBarImageScanner *scanner = reader.scanner;
    [scanner setSymbology:ZBAR_I25 config:ZBAR_CFG_ENABLE to:0];
    [self presentModalViewController:reader animated:YES];
    [reader release];
}
//将上面这个方法注册给“开始扫描”按钮:
[QRBut addTarget:self action:@selector(startScan:) forControlEvents:UIControlEventTouchUpInside];
//扫描成功后,会自动调用此方法
- (void) imagePickerController: (UIImagePickerController*) picker didFinishPickingMediaWithInfo: (NSDictionary*) info
{
    UIImage *image = [info objectForKey: UIImagePickerControllerOriginalImage];    
    id<NSFastEnumeration> results = [info objectForKey: ZBarReaderControllerResults];
    ZBarSymbol *symbol = nil;    
    for(symbol in results){
        break;
    }    
    if(!symbol || !image){
        return;
    }    
    NSLog(@"symbol.data = %@", symbol.data);  
    [self sendRQcode:symbol.data];  
    [picker dismissModalViewControllerAnimated: YES];
} //imagePickerController

//取得二维码后,通过http方式发送,然后解析返回的json数据

- (void) sendRQcode:(NSString*)code
{
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    NSDate* dat = [NSDate dateWithTimeIntervalSinceNow:0];
    NSTimeInterval a=[dat timeIntervalSince1970];
    NSString *timeString = [NSString stringWithFormat:@"%f", a];
    NSHTTPURLResponse* urlResponse = nil;
    NSError *error = [[NSError alloc] init];
    NSLog(@"-------loginClick------user:%@", timeString);
    NSString *url = [[[[[@"http://xxxxxx/client_login.php?user=" stringByAppendingString:user]                     
            stringByAppendingString:@"&source="] stringByAppendingString:code]
            stringByAppendingString:@"&time="] stringByAppendingString:timeString];
    [request setURL:[NSURL URLWithString:url]];
    [request setHTTPMethod:@"GET"];
    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];  
    //发送请求  
    NSData *returnData = [NSURLConnection sendSynchronousRequest:request 
            returningResponse:&urlResponse error:&error];
    NSLog(@"-------sendRQcode--status:------%d", [urlResponse statusCode]);
    NSString *login = @"0";
    if(returnData != NULL && [urlResponse statusCode] == 200) {
        //解析json
        NSDictionary *data = [returnData objectFromJSONData];
        NSLog(@"-------sendRQcode----returnData:------%@", data);
        login = [data objectForKey:@"login"];
    }
    NSLog(@"-------sendRQcode----login:------%@", login);
    msg = @"";
    if([login isEqual: @"1"]){
        msg = @"登录成功!";
    }else if([login isEqual:@"0"]){
        msg = @"网络连接错误,请检查网络设置后重试!";
    }else{
        msg = [[@"未知错误(login:" stringByAppendingString:login] stringByAppendingString:@"),请检查网络设置后重试!"];
    }
    NSLog(@"-------sendRQcode----msg:------%@", msg);
    [self alertWithMessage:msg];
}//sendRQcode

———–
代码就展示这么多,具体的,请访问github:https://github.com/jklgithub/qrcode_login
本文为本人原创,转载请注明地址:http://www.jiangkl.com/2012/10/%E4%BA%8C%E7%BB%B4%E7%A0%81%E7%99%BB%E5%BD%95_qrcode_zbar/
演示地址:dev.jiangkl.com (mongo不太稳定,测试不通的话可以给我留言)

倒塌集

脑残的本本设计

专门给左撇子设计的本本

堆积的接口


————-

参考:http://tech.ifeng.com/digi/nbook/evaluation/detail_2012_05/21/14686554_0.shtml

业界杂谈 他山石

[转]抓大放小,从粗到精

作为产品经理的你,洋洋洒洒的整理完产品的功能列表,长舒一口气,看,爷的产品多强大,规划了这么多牛掰闪闪的功能;作为交互设计师的你,头晕眼花的画完产品的原型和流程,暗自窃喜道,看,咱的流程多细致,梳理了那么多特殊情况和可能性;作为视觉设计师的你,设计了好多个华丽丽的界面,你为每一个页面进行了精心的雕琢,期待用户见到每一个页面都竖起大拇指说这个界面真漂亮;作为开发人员的你,搭建完框架之后,发现每个模块都有评审时漏掉的细节,一个模块一个模块的赶进度,导致你精疲力尽力不从心。

其实,在一个产品里,并不是所有的功能都那么重要的,如果产品经理只是交付一个功能列表,而不做需求优先级设定的话,产品可能沦为没有主心骨的产品,交互设计师设计的时候,不确定主要任务是什么;视觉设计师设计的的时候,不确定哪些界面和模块要提供更精致的设计;开发人员开发的时候,不知道哪些功能该设定更高的开发优先级,于是就会形成大家都在搅浆糊的状态,可能因为某些弱弱的分支流程的复杂性,导致开发人员花了大量的时间去攻克难题;可能因为某个不那么重要的设置界面中,UI增加了复杂的转场效果,导致开发人员搞到头破血流;可能因为开发人员捡着简单的功能先做,导致复杂的重要功能到最后才被草草攻克,一堆bug。别在抱怨各个角色不给力什么的了,想想自己的需求的分析是否到位,是否给你的需求排排等级,哪些对解决产品的商业价值+用户价值有最大的帮助,优先实现它,不重要的,不着急的,可以次优先级实现。

产品功能就像镜头里的花,如果你的镜头里,全是花,会因为全是亮点而变得没有亮点;如果你的镜头里,聚焦于一朵最娇艳的话,亮点就轻松浮现了。但有时候,说不做什么比说做什么还要难。必须每次改版,都上一些新功能,才能让用户知道我们在持续改进,才能让老板知道我们的团队充满战斗力。针对这些要上的功能(或来源于客户,或来源于老板,或来源于自己突发奇想),如果你经过了反复的调研,结论是做的意义不大,你甚至都不敢汇报,还是要硬着头皮上新功能。直到程序底层架构出了大问题,才不得不停下来做代码重构。

“People think focus means saying yes to the thing you’ve got to focus on. But that’s not what it means at all. It means saying no to the hundred other good ideas that there are. You have to pick carefully. I’m actually as proud of the things we haven’t done as the things I have done. Innovation is saying ‘no’ to 1,000 things. ——Steve Jobs

是的,不得不说,乔布斯是一个睿智的产品经理,他眼光独到,敢于取舍,会为了一个产品秘密研发几年,终于厚积薄发。国内环境不太一样,是非成败,瞬息万变,没有一个老板乐意让团队研发那么久,下那么大赌注在一款产品上。他们希望马上看到成绩,逼得团队甚至没有太多时间去深入调研,只能找到一些已经被证明可用的模式,Copy to China,虽说有些变态,可更多的是无奈。

即便如此,产品经理仍然可以讲清楚,产品的核心模块、核心功能是什么。就像这样一个金字塔,塔尖上的是最重要的需求,没有这些,就没有产品价值。

而一个交互设计师,则需要在了解清楚主要需求之后,对应分解到主要任务流程,你需要花80%的精力去设计那20%的重要任务流程,而这20%的重要任务流程,又足以解决80%的用户的核心需求。

有两个技巧让你不会劳心劳力又没成绩——1.抓大放小,要精心雕琢主要任务快速完成次要任务;2.从粗到精,不要上来就陷入到细节中去

其实花了这么多笔墨,只是讲了一个简单的道理,学会做减法,学会排优先级,学会抓主要矛盾。但这本身就是一件知易行难的事,还需要在实践中不断磨练。
———-
转自:http://ucdchina.com/snap/10368

Hello World 业界杂谈 日志

上帝之手

刚开始做程序员的时候,眼看着一行行代码编程变成功能,经常觉得自己是在创造一个世界,自己是上帝~~这时还都是做后台,按要求做个功能,具体做成什么样子基本上都是自己定~~最大的经验时:一个系统,就如同一间房子,用户进了门以后,在里面要能顺顺利利的做各种事情,然后还要能顺顺利利的出来~~面对一条错误数据引起系统彻底不能用的问题,我经常给同事打比方说:上帝打了一个喷嚏,结果世界崩溃了

后来,随着技术水平的逐渐提高,开始做前台的东西:有产品人员设计具体产品,自己只是把这个产品做出来~~这时才发觉:做产品的才是上帝,程序员不过是给他们打工的建筑工人,能够自己发挥的余地很小。。。最郁闷的是“上帝”总是把握不准/或者“上帝”的老板不满意,产品设计总是变来变去,而程序员面对这些变化,大部分时候只能唯命是从

今天开了整整一天的会:所谓“产品冲刺计划会”,估计明天/后天还要持续。最有意思的是这个会的前半部分:产品人员要把自己的产品详详细细的给大家讲清楚~~然后大家开始发问,可能是关于每一个细节的问题:一个链接/一个按钮/甚至一个文字……然后产品人员自己才发觉:呀,这里没考虑/哦,这是个问题……挺好,集体会诊

这时,我突然想:当初上帝决定要创造世界的时候,是不是也开了这种会:为什么要有人?为什么人要分男女?……为什么π是3.14?为什么…….上帝统统回答:因为老子是上帝!哈哈