文章正文
址自动识别现在普遍,特别是用在快递填写地址,姓名,手机号码的时候,会把这些按照一定的规范填写后,点击自动识别后,会自动填写到各自的input。最近也简单的实现了这个功能,给后台添加用户的时候,自动识别地址。以下是效果图
具体问题具体分析!代码实现基于laravel完成。一个laravel完整的功能得具备这些:路由route,Model, View, Controller, 我这里用的有依赖注入服务容器等功能,当然,用到地址,你首先要有地址库。。。
下面来看看是如何实现的,这里我只贴出核心代码
UsersController控制器
在这里新建构造函数,实现容器的依赖注入 UsersRepository
/** @var UserRepository */
private $userRepository;
public function __construct (UsersRepository $userRepo)
{
$this ->userRepository = $userRepo;
}
接下来就新建地址识别的方法, $discernDel 接收的数据是从前端传过来的,后面再贴前端代码。 业务代码处理交给容器 UsersRepository 里的方法 getDiscern 处理
/**
* Function:地址识别
* Author:cyw0413
* @param Request $request
* @return IlluminateContractsRoutingResponseFactory|IlluminateHttpResponse|
* LaravelLumenHttpResponseFactory|SymfonyComponentHttpFoundationResponse
*/
public function getDiscern (Request $request)
{
$discernDel = $request->input( 'discernDel' );
try {
DB::beginTransaction();
$ address = $this ->userRepository->getDiscern($discernDel);
DB::commit();
} catch ( Exception $e){
DB::rollBack();
$ msg = "信息提示:" .$e->getMessage(). ",行:" .$e->getLine();
return response([ 'code' => 0 , 'msg' =>$msg]);
}
return response([ 'code' => 1 , 'msg' =>$address]); //地址识别完成
}
来看看 userRepository容器处理地址识别的各种业务代码
/**
* Function:识别地址
* Author:cyw0413
*/
public function getDiscern ($discernDel)
{
if ( empty ($discernDel)) {
throw new Exception ( "请传入要识别的地址" );
}
$discernDel_left = explode ( '[' , $discernDel);
if (! isset ($discernDel_left[ 1 ])) {
throw new Exception ( "你填写的地址规则错误,手机号码应该用[]" );
}
$discernDel_right = explode ( ']' , $discernDel_left[ 1 ]);
if (! isset ($discernDel_right[ 1 ]) || empty ($discernDel_right[ 1 ])) {
throw new Exception ( "你填写的地址规则错误,手机号码应该用[]" );
}
$name = $discernDel_left[ 0 ];
if ( empty ($name)) {
throw new Exception ( "你填写的姓名有误!" );
}
$ mobile = $discernDel_right[ 0 ];
if ( empty ($mobile) || checkMobile($mobile) == 0 ) {
throw new Exception ( "你填写的手机号码格式有误!" );
}
$address = trim ($discernDel_right[ 1 ]);
if ( empty ($address)) {
throw new Exception ( "你填写的地址不能为空" );
}
$var_address = $this ->getAddressArrar($address);
$var_address[ 'name' ] = $name;
$var_address[ 'mobile' ] = $mobile;
return $var_address;
}
上面的方法处理手机,名称,和地址处理,地址处理有些繁杂,因为有时候填写的地址有不一样的,比如广西省,有些就填写广西壮族自治区,所以 getAddressArrar 方法处理地址匹配信息,根据自己的业务做调整,如下
/**
* Function:地址的处理
* Author:cyw0413
* @param $address
* @return array
* @throws Exception
*/
function getAddressArrar ($address) {
// 获取所有地址递归列表
$regions = $this ->getRegions();
// 初始化数据
$province = $city = $district = [];
// 先查找省份-第一级地区
$province = $this ->checkAddress($address, $regions);
if ($province){
$province_arr = [ '110000' , '300000' , '404100' , '310000' ]; //4个 市辖区 如果地址不存在二级(市辖区,县),则特殊处理
if (! isset ($province[ 'region_code' ])){
throw new Exception ( "请正确填写省份(市辖区)" );
}
// 查找城市-第二级地区
$city = $this ->checkAddress($address, $province[ 'list' ]);
//这里只处理4个市辖区,可能还有多种情况,待发现
if (in_array($province[ 'region_code' ],$province_arr) && count($city[ 'list' ]) == 0 ){
$city = $this ->checkAddress( '市辖区' , $province[ 'list' ]);
if ($city){
// 查找地区-第三级地区
$district = $this ->checkAddress($address, $city[ 'list' ]);
//如果没有找到,则查找另外一个二级地区
if (! isset ($district[ 'region_code' ])){
$city = $this ->checkAddress( '县' , $province[ 'list' ]);
// 查找地区-第三级地区
$district = $this ->checkAddress($address, $city[ 'list' ]);
}
}
} else {
if ($city){
// 查找地区-第三级地区
$district = $this ->checkAddress($address, $city[ 'list' ]);
}
}
} else {
//省份不填,报错误
throw new Exception ( "省份没填写,请检查" );
}
return $this ->getAddressInfo($address, $province, $city, $district);
}
/**
* 匹配正确的城市地址
* @param $address
* @param $city_list
* @param int $force
* @param int $str_len
* @return array
**/
function checkAddress ($address, $city_list, $force=false, $str_len= 2 ) {
$num = 0 ;
$list = array ();
$result = array ();
// 遍历所有可能存在的城市
foreach ($city_list as $city_key=>$city){
$city_name = mb_substr($city[ 'region_name' ], 0 , $str_len, 'utf-8' );
// 判断是否存包含当前地址字符
$city_arr = explode($city_name, $address);
// 如果存在相关字眼,保存该地址的所有子地址
if (count($city_arr) >= 2 ){
// 必须名称长度同时达到当前比对长度
if ( strlen ($city[ 'region_name' ]) < $str_len){
continue ;
}
$num ++;
if ( isset ($city[ 'child' ])){
$list = $list + $city[ 'child' ];
}
$result[] = array (
'region_code' => $city_key,
'region_name' => $city[ 'region_name' ],
'list' =>$list,
);
}
}
// 如果有多个存在,则加大字符匹配长度
if ($num > 1 || $force){
$region_name1 = $result[ 0 ][ 'region_name' ];
$region_name2 = $result[ 1 ][ 'region_name' ];
if (strlen($region_name1) == strlen($region_name2) && strlen($region_name1) == $str_len){
$region_id1 = $result[ 0 ][ 'region_code' ];
$region_id2 = $result[ 1 ][ 'region_code' ];
$index = $region_id1 > $region_id2 ? 1 : 0 ;
$result = $result[$index];
return $result;
}
return $this ->checkAddress($address, $city_list, $force, $str_len+ 1 );
} else {
$result[ 0 ][ 'list' ] = $list;
return $result[ 0 ];
}
}
/**
* 根据原地址返回详细信息
* @param $address
* @param $province
* @param $city
* @param $area
* @return array
**/
function getAddressInfo ($address, $province, $city, $district) {
// 查找最后出现的地址 - 截取详细信息
if (! isset ($province[ 'region_name' ])){
throw new Exception ( "请检查并正确填写省份(市辖区)" );
}
if (! isset ($city[ 'region_name' ])){
throw new Exception ( "请检查并正确填写城市" );
}
if (! isset ($district[ 'region_name' ])){
throw new Exception ( "请检查并正确填写区域(县/区/镇)" );
}
$find_str = '' ;
if ($province[ 'region_name' ]){
$find_str = $province[ 'region_name' ];
if ($city[ 'region_name' ]){
$find_str = $city[ 'region_name' ];
if ( isset ($district[ 'region_name' ]) && $district[ 'region_name' ]){
$find_str = $district[ 'region_name' ];
}
}
}
// 截取详细的信息
$find_str_len = mb_strlen($find_str, 'utf-8' );
for ($i= 0 ; $i<$find_str_len -1 ; $i++){
$substr = mb_substr($find_str, 0 ,$find_str_len - $i, 'utf-8' );
$end_index = mb_strpos($address, $substr);
if ($end_index){
$address = mb_substr($address, $end_index + mb_strlen($substr) , mb_strlen($address) - $end_index);
}
}
! empty ($find_str) && $find_str = '|S*' . $find_str;
$area[ 'info' ] = preg_replace( "/s*|,|,|:|:{$find_str}/i" , '' , $address);
if ( empty ($area[ 'info' ])){
throw new Exception ( "详细地址不存在,请检查" );
}
return $address = [
'province' => $province[ 'region_code' ],
'city' => $city[ 'region_code' ],
'district' => $district[ 'region_code' ],
'info' => $area[ 'info' ]
];
}
前端html部分代码
基本上能看得懂的。 jquery 用到 getDiscern(); 方法,手机号码,姓名,地址等input这里就不一一列出了。大家根据下面的jquery都能想象到
<div class= "form-group" >
{!! Form::label( 'discern' , '自动识别地址:' ,[ 'class' => 'control-label col-sm-2' ]) !!}
<div class= "col-sm-5" >
{!! Form::textarea( 'discern' , '' , [ 'class' => 'form-textarea form-control form-discern' , 'rows' => 3]) !!}
</div>
<div class= "col-sm-3" style= "height: 75px;" >
<button type = "button" class= "btn btn-info btn-sm discern" onclick= "getDiscern();" >提交识别</button>
<small class= "ruleGet" style= "color: #676a74;" >*查看模板</small>
</div>
</div>
jquery代码部分
ajax post后交给url: getDiscern 处理,这个就是上面controller的方法,success返回的数据后再追加到每个input里,最后再清除掉自动识别地址框的数据
/**
* 地址识别
* @returns {boolean}
*/
function getDiscern () {
var discernDel = $( ".form-discern" ).val();
if (!discernDel){
alert( "请输入要识别的地址" );
return false ;
}
$.ajax({
type : 'POST' ,
url : "{!! route('admin.user.getDiscern') !!}" ,
data : {
'_token' : csrf_token(),
'discernDel' : discernDel
},
dataType : 'json' ,
timeout : 50000 ,
success : function ( res ) {
if (res.code == 1 ) {
$( "input[name='addr[linkman]']" ).val(res.msg.name);
$( "input[name='user_name']" ).val(res.msg.mobile);
$( "input[name='addr[address]']" ).val(res.msg.info);
//触发change事件
$( '#province' ).val(res.msg.province). trigger ( 'change' );
$( '#city' ).val(res.msg.city).trigger( 'change' );
$( '#area' ).val(res.msg.district).trigger( 'change' );
//识别后清除
$( ".form-discern" ).val( "" );
} else {
alert(res.msg);
}
}
})
}
整个过程简单,又清晰明了,以上就是小编的代码,分享给大家,觉得哪个地方不对劲的,欢迎留言吐槽!