前言
这是2015年的一个项目,基于Drupal7+Commerce模块进行开发。由于Commerce自带的购物流程比较复杂,而且界面简陋,用起来也不方便,所以需要进行彻底的重新设计。过程中遇到不少问题,很多是以前没有遇到过的,后来通过大量的Google搜索以及阅读API文档,才得以全部解决。
准备
由于页面多处使用了AJAX操作,为了方便,引入了AngularJS 1.x版本。另外使用了部分Semantic UI组件。Drupal部分为了保持性能以及代码简介,尽量少用模块。页面全部使用定制模版,为了不和Commerce自带的页面冲突,购物车以及结账页面URL也需要修改。
开始
HTML页面制作的时候也遇到了一些问题,要求必须保持等比缩放,但是由于各种平台以及浏览器兼容性问题,也折腾了很久,尝试过rem和viewport,最终选择了viewport,这里就不细说了,另外写一篇文章再说。
主要讲Drupal,从商品页面开始说起,先上一张图。
商品属性选择,Commerce默认的属性选择界面太丑,于是重新做成这样。方法是先把载入的商品属性和相应的商品ID保存在隐藏域里,然后用AngularJS的方式把属性列表绑定在弹出框里,当用户点击“放入购物袋”按钮时(这里需要用JS判断当前的添加到购物车按钮有没有被禁用),弹出属性供用户选择,用户选择并点击确定后,从隐藏域中取出商品ID,把添加到购物车表单内相应的值修改,并模拟用户点击添加到购物车按钮。这样就完成了加入购物车的操作。
因为AngularJS需要配合HTML工作,所以这里的代码并不通用,就不贴上来了。
购物车表单,这里把URL修改为 /bag ,购物袋。使用 hook_menu 定义页面。
function mymodule_menu() {
//重写购物车页面
'bag' => array(
'type' => MENU_NORMAL_ITEM,
'title' => '购物袋',
'page callback' => 'mymodule_commerce_cart',
'access callback' => TRUE
),
}
/**
* 重写购物车页面
* 返回购物车内的行项
*/
function ajax_plug_commerce_cart() {
global $user;
$order = commerce_cart_order_load($user->uid);
$line_items = array();
if(!empty($order))
$line_items = entity_metadata_wrapper('commerce_order', $order)->commerce_line_items->value();
// 这里的custom_commerce_cart是使用 hook_theme 自定义的模板,传递购物车订单内的行项
return theme('custom_commerce_cart', array('vars' => array('rows' => $line_items)));
}
这里自定义一个页面(hook_menu)和一个模板(hook_theme),然后提取用户的购物车订单(commerce_cart_order_load)内的行项(entity_metadata_wrapper('commerce_order', $order)->commerce_line_items->value()),交给模板来渲染,最终就是新的购物车页面。这个页面的商品数量部件修改值以后自动以AJAX的方式提交到后台,然后返回重新计算后的商品价格以及订单总价。
AJAX提交的方式就不讲了,这里讲一下PHP更新商品数量的方法。数据提交地址同样适用 hook_menu 定义,接受JSON数据,传递的数据包括行项ID还有修改后的数量。具体调用到的方法,首先根据UID载入购物车订单,commerce_cart_order_load方法, 然后根据传递的行项ID找到需要更新的行项,把行项的quantity属性设置成传递过来的数量,调用 commerce_line_item_save 方法保存行项,然后调用 commerce_order_save 保存订单,最后获取订单的 commerce_order_total 属性,获取订单总价,返回JSON 数据。
结算页面。这个页面添加地址和优惠券稍微复杂一点。地址也是通过AJAX的方式提交到后台保存的,获取用户所有收获地址,使用 commerce_customer_profile_load_multiple 方法,添加一个新的地址,使用 commerce_customer_profile_new 方法,选择好地址后,修改订单的 commerce_customer_billing 属性,设置收货地址。
使用优惠券的原理和地址类似,使用 commerce_coupon_redeem_coupon 应用优惠券到订单,这个网站的优惠券还设置了某些商品不允许使用优惠券等,这里就不赘述了。
还有一个比较复杂的地方就是微信支付,由于没有现成的模块,于是根据这个网站的需求重新开发了一个,调用微信的JSAPI支付功能(仅支持微信端),大致思路就是进入结算页面的时候,检查用户的浏览器类型,如果是微信内,则调用微信支付SDK的下单功能生成相应金额的订单,然后在页面加入调用JSAPI的代码,当用户点击提交订单时,调用支付方法。用户操作完成支付后,更新订单状态。
最后是用户中心页面,这个页面有几个部分,主要是订单列表、余额、修改密码以及邮箱等等。
订单列表是使用AngularJS读取后台数据生成的,一次读取几条,点击 更多 继续载入其他订单。余额是使用 userpoints 模块积分模拟的,配合Commerce Userpoints 以及 Commerce Userpoints Payment method 模块实现积分支付功能。
结束
这个项目最主要的问题是对Drupal各类的API不熟悉,所以查阅大量的API文档才得以解决问题。过程中也遇到一些坑,例如折扣优惠券和定额优惠券的不同行为,总之解决问题的过程是比较痛苦的,解决完了之后又很有成就感。通过这个项目对Drupal以及Commerce的理解也深入了不少。不过Drupal8已经出来了,还有更多的坑在等着呢。