文章正文
址自动识别现在普遍,特别是用在快递填写地址,姓名,手机号码的时候,会把这些按照一定的规范填写后,点选自动识别后,会自动填写到各自的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\']) 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-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都能想象到
"form-group">
{!! Form::label(\'discern\', \'自动识别地址:\',[\'class\' => \'control-label col-sm-2\']) !!}
"col-sm-5">
{!! Form::textarea(\'discern\', \'\', [\'class\' => \'form-textarea form-control form-discern\',\'rows\' => 3]) !!}
"col-sm-3" style="height: 75px;">
type="button" class="btn btn-info btn-sm discern" onclick="getDiscern();" >提交识别
"ruleGet" style="color: #676a74;">*检视模板
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);
}
}
})
}
整个过程简单,又清晰明了,以上就是小编的程式码,分享给大家,觉得哪个地方不对劲的,欢迎留言吐槽!